mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-12 13:31:52 +00:00
RESTStorage should not need to know about async behavior
Also make sure all POST operations return 201 by default. Removes the remainder of the asych logic in RESTStorage and leaves it up to the API server to expose that behavior.
This commit is contained in:
parent
79cb93002e
commit
26f08b7807
@ -18,9 +18,9 @@ package binding
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
@ -44,15 +44,13 @@ func (*REST) New() runtime.Object {
|
||||
}
|
||||
|
||||
// Create attempts to make the assignment indicated by the binding it recieves.
|
||||
func (b *REST) Create(ctx api.Context, obj runtime.Object) (<-chan apiserver.RESTResult, error) {
|
||||
func (b *REST) Create(ctx api.Context, obj runtime.Object) (runtime.Object, error) {
|
||||
binding, ok := obj.(*api.Binding)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("incorrect type: %#v", obj)
|
||||
}
|
||||
return apiserver.MakeAsync(func() (runtime.Object, error) {
|
||||
if err := b.registry.ApplyBinding(ctx, binding); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &api.Status{Status: api.StatusSuccess}, nil
|
||||
}), nil
|
||||
if err := b.registry.ApplyBinding(ctx, binding); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &api.Status{Status: api.StatusSuccess, Code: http.StatusCreated}, nil
|
||||
}
|
||||
|
@ -71,22 +71,20 @@ func TestRESTPost(t *testing.T) {
|
||||
}
|
||||
ctx := api.NewContext()
|
||||
b := NewREST(mockRegistry)
|
||||
resultChan, err := b.Create(ctx, item.b)
|
||||
if err != nil {
|
||||
result, err := b.Create(ctx, item.b)
|
||||
if err != nil && item.err == nil {
|
||||
t.Errorf("Unexpected error %v", err)
|
||||
continue
|
||||
}
|
||||
var expect *api.Status
|
||||
if item.err == nil {
|
||||
expect = &api.Status{Status: api.StatusSuccess}
|
||||
} else {
|
||||
expect = &api.Status{
|
||||
Status: api.StatusFailure,
|
||||
Code: http.StatusInternalServerError,
|
||||
Message: item.err.Error(),
|
||||
}
|
||||
if err == nil && item.err != nil {
|
||||
t.Errorf("Unexpected error %v", err)
|
||||
continue
|
||||
}
|
||||
if e, a := expect, (<-resultChan).Object; !reflect.DeepEqual(e, a) {
|
||||
var expect interface{}
|
||||
if item.err == nil {
|
||||
expect = &api.Status{Status: api.StatusSuccess, Code: http.StatusCreated}
|
||||
}
|
||||
if e, a := expect, result; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("%v: expected %#v, got %#v", i, e, a)
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ func NewREST(registry Registry, podLister PodLister) *REST {
|
||||
}
|
||||
|
||||
// Create registers the given ReplicationController.
|
||||
func (rs *REST) Create(ctx api.Context, obj runtime.Object) (<-chan apiserver.RESTResult, error) {
|
||||
func (rs *REST) Create(ctx api.Context, obj runtime.Object) (runtime.Object, error) {
|
||||
controller, ok := obj.(*api.ReplicationController)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("not a replication controller: %#v", obj)
|
||||
@ -60,20 +60,16 @@ func (rs *REST) Create(ctx api.Context, obj runtime.Object) (<-chan apiserver.RE
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return apiserver.MakeAsync(func() (runtime.Object, error) {
|
||||
if err := rs.registry.CreateController(ctx, controller); err != nil {
|
||||
err = rest.CheckGeneratedNameError(rest.ReplicationControllers, err, controller)
|
||||
return apiserver.RESTResult{}, err
|
||||
}
|
||||
return rs.registry.GetController(ctx, controller.Name)
|
||||
}), nil
|
||||
if err := rs.registry.CreateController(ctx, controller); err != nil {
|
||||
err = rest.CheckGeneratedNameError(rest.ReplicationControllers, err, controller)
|
||||
return apiserver.RESTResult{}, err
|
||||
}
|
||||
return rs.registry.GetController(ctx, controller.Name)
|
||||
}
|
||||
|
||||
// Delete asynchronously deletes the ReplicationController specified by its id.
|
||||
func (rs *REST) Delete(ctx api.Context, id string) (<-chan apiserver.RESTResult, error) {
|
||||
return apiserver.MakeAsync(func() (runtime.Object, error) {
|
||||
return &api.Status{Status: api.StatusSuccess}, rs.registry.DeleteController(ctx, id)
|
||||
}), nil
|
||||
func (rs *REST) Delete(ctx api.Context, id string) (runtime.Object, error) {
|
||||
return &api.Status{Status: api.StatusSuccess}, rs.registry.DeleteController(ctx, id)
|
||||
}
|
||||
|
||||
// Get obtains the ReplicationController specified by its id.
|
||||
@ -117,24 +113,23 @@ func (*REST) NewList() runtime.Object {
|
||||
|
||||
// Update replaces a given ReplicationController instance with an existing
|
||||
// instance in storage.registry.
|
||||
func (rs *REST) Update(ctx api.Context, obj runtime.Object) (<-chan apiserver.RESTResult, error) {
|
||||
func (rs *REST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
||||
controller, ok := obj.(*api.ReplicationController)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("not a replication controller: %#v", obj)
|
||||
return nil, false, fmt.Errorf("not a replication controller: %#v", obj)
|
||||
}
|
||||
if !api.ValidNamespace(ctx, &controller.ObjectMeta) {
|
||||
return nil, errors.NewConflict("controller", controller.Namespace, fmt.Errorf("Controller.Namespace does not match the provided context"))
|
||||
return nil, false, errors.NewConflict("controller", controller.Namespace, fmt.Errorf("Controller.Namespace does not match the provided context"))
|
||||
}
|
||||
if errs := validation.ValidateReplicationController(controller); len(errs) > 0 {
|
||||
return nil, errors.NewInvalid("replicationController", controller.Name, errs)
|
||||
return nil, false, errors.NewInvalid("replicationController", controller.Name, errs)
|
||||
}
|
||||
return apiserver.MakeAsync(func() (runtime.Object, error) {
|
||||
err := rs.registry.UpdateController(ctx, controller)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rs.registry.GetController(ctx, controller.Name)
|
||||
}), nil
|
||||
err := rs.registry.UpdateController(ctx, controller)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
out, err := rs.registry.GetController(ctx, controller.Name)
|
||||
return out, false, err
|
||||
}
|
||||
|
||||
// Watch returns ReplicationController events via a watch.Interface.
|
||||
|
@ -22,7 +22,6 @@ import (
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
|
||||
@ -268,23 +267,17 @@ func TestCreateController(t *testing.T) {
|
||||
},
|
||||
}
|
||||
ctx := api.NewDefaultContext()
|
||||
channel, err := storage.Create(ctx, controller)
|
||||
obj, err := storage.Create(ctx, controller)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
if obj == nil {
|
||||
t.Errorf("unexpected object")
|
||||
}
|
||||
if !api.HasObjectMetaSystemFieldValues(&controller.ObjectMeta) {
|
||||
t.Errorf("storage did not populate object meta field values")
|
||||
}
|
||||
|
||||
select {
|
||||
case <-channel:
|
||||
// expected case
|
||||
case <-time.After(time.Millisecond * 100):
|
||||
t.Error("Unexpected timeout from async channel")
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: remove, covered by TestCreate
|
||||
@ -338,9 +331,9 @@ func TestControllerStorageValidatesUpdate(t *testing.T) {
|
||||
}
|
||||
ctx := api.NewDefaultContext()
|
||||
for _, failureCase := range failureCases {
|
||||
c, err := storage.Update(ctx, &failureCase)
|
||||
if c != nil {
|
||||
t.Errorf("Expected nil channel")
|
||||
c, created, err := storage.Update(ctx, &failureCase)
|
||||
if c != nil || created {
|
||||
t.Errorf("Expected nil object and not created")
|
||||
}
|
||||
if !errors.IsInvalid(err) {
|
||||
t.Errorf("Expected to get an invalid resource error, got %v", err)
|
||||
@ -441,9 +434,9 @@ func TestUpdateControllerWithConflictingNamespace(t *testing.T) {
|
||||
}
|
||||
|
||||
ctx := api.NewDefaultContext()
|
||||
channel, err := storage.Update(ctx, controller)
|
||||
if channel != nil {
|
||||
t.Error("Expected a nil channel, but we got a value")
|
||||
obj, created, err := storage.Update(ctx, controller)
|
||||
if obj != nil || created {
|
||||
t.Error("Expected a nil object, but we got a value or created was true")
|
||||
}
|
||||
if err == nil {
|
||||
t.Errorf("Expected an error, but we didn't get one")
|
||||
|
@ -21,7 +21,6 @@ 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/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||
@ -59,7 +58,7 @@ func (rs *REST) Watch(ctx api.Context, label, field labels.Selector, resourceVer
|
||||
}
|
||||
|
||||
// Create satisfies the RESTStorage interface.
|
||||
func (rs *REST) Create(ctx api.Context, obj runtime.Object) (<-chan apiserver.RESTResult, error) {
|
||||
func (rs *REST) Create(ctx api.Context, obj runtime.Object) (runtime.Object, error) {
|
||||
endpoints, ok := obj.(*api.Endpoints)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("not an endpoints: %#v", obj)
|
||||
@ -72,28 +71,25 @@ func (rs *REST) Create(ctx api.Context, obj runtime.Object) (<-chan apiserver.RE
|
||||
}
|
||||
api.FillObjectMetaSystemFields(ctx, &endpoints.ObjectMeta)
|
||||
|
||||
return apiserver.MakeAsync(func() (runtime.Object, error) {
|
||||
err := rs.registry.UpdateEndpoints(ctx, endpoints)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rs.registry.GetEndpoints(ctx, endpoints.Name)
|
||||
}), nil
|
||||
err := rs.registry.UpdateEndpoints(ctx, endpoints)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rs.registry.GetEndpoints(ctx, endpoints.Name)
|
||||
}
|
||||
|
||||
// Update satisfies the RESTStorage interface.
|
||||
func (rs *REST) Update(ctx api.Context, obj runtime.Object) (<-chan apiserver.RESTResult, error) {
|
||||
func (rs *REST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
||||
endpoints, ok := obj.(*api.Endpoints)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("not an endpoints: %#v", obj)
|
||||
return nil, false, fmt.Errorf("not an endpoints: %#v", obj)
|
||||
}
|
||||
return apiserver.MakeAsync(func() (runtime.Object, error) {
|
||||
err := rs.registry.UpdateEndpoints(ctx, endpoints)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rs.registry.GetEndpoints(ctx, endpoints.Name)
|
||||
}), nil
|
||||
err := rs.registry.UpdateEndpoints(ctx, endpoints)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
out, err := rs.registry.GetEndpoints(ctx, endpoints.Name)
|
||||
return out, false, err
|
||||
}
|
||||
|
||||
// New implements the RESTStorage interface.
|
||||
|
@ -22,7 +22,6 @@ import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
@ -42,7 +41,7 @@ func NewREST(registry generic.Registry) *REST {
|
||||
}
|
||||
}
|
||||
|
||||
func (rs *REST) Create(ctx api.Context, obj runtime.Object) (<-chan apiserver.RESTResult, error) {
|
||||
func (rs *REST) Create(ctx api.Context, obj runtime.Object) (runtime.Object, error) {
|
||||
event, ok := obj.(*api.Event)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid object type")
|
||||
@ -57,41 +56,38 @@ func (rs *REST) Create(ctx api.Context, obj runtime.Object) (<-chan apiserver.RE
|
||||
}
|
||||
api.FillObjectMetaSystemFields(ctx, &event.ObjectMeta)
|
||||
|
||||
return apiserver.MakeAsync(func() (runtime.Object, error) {
|
||||
err := rs.registry.Create(ctx, event.Name, event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rs.registry.Get(ctx, event.Name)
|
||||
}), nil
|
||||
err := rs.registry.Create(ctx, event.Name, event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rs.registry.Get(ctx, event.Name)
|
||||
}
|
||||
|
||||
// Update replaces an existing Event instance in storage.registry, with the given instance.
|
||||
func (rs *REST) Update(ctx api.Context, obj runtime.Object) (<-chan apiserver.RESTResult, error) {
|
||||
func (rs *REST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
||||
event, ok := obj.(*api.Event)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("not an event object: %#v", obj)
|
||||
return nil, false, fmt.Errorf("not an event object: %#v", obj)
|
||||
}
|
||||
if api.NamespaceValue(ctx) != "" {
|
||||
if !api.ValidNamespace(ctx, &event.ObjectMeta) {
|
||||
return nil, errors.NewConflict("event", event.Namespace, fmt.Errorf("event.namespace does not match the provided context"))
|
||||
return nil, false, errors.NewConflict("event", event.Namespace, fmt.Errorf("event.namespace does not match the provided context"))
|
||||
}
|
||||
}
|
||||
if errs := validation.ValidateEvent(event); len(errs) > 0 {
|
||||
return nil, errors.NewInvalid("event", event.Name, errs)
|
||||
return nil, false, errors.NewInvalid("event", event.Name, errs)
|
||||
}
|
||||
api.FillObjectMetaSystemFields(ctx, &event.ObjectMeta)
|
||||
|
||||
return apiserver.MakeAsync(func() (runtime.Object, error) {
|
||||
err := rs.registry.Update(ctx, event.Name, event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rs.registry.Get(ctx, event.Name)
|
||||
}), nil
|
||||
err := rs.registry.Update(ctx, event.Name, event)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
out, err := rs.registry.Get(ctx, event.Name)
|
||||
return out, false, err
|
||||
}
|
||||
|
||||
func (rs *REST) Delete(ctx api.Context, id string) (<-chan apiserver.RESTResult, error) {
|
||||
func (rs *REST) Delete(ctx api.Context, id string) (runtime.Object, error) {
|
||||
obj, err := rs.registry.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -100,9 +96,7 @@ func (rs *REST) Delete(ctx api.Context, id string) (<-chan apiserver.RESTResult,
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid object type")
|
||||
}
|
||||
return apiserver.MakeAsync(func() (runtime.Object, error) {
|
||||
return &api.Status{Status: api.StatusSuccess}, rs.registry.Delete(ctx, id)
|
||||
}), nil
|
||||
return &api.Status{Status: api.StatusSuccess}, rs.registry.Delete(ctx, id)
|
||||
}
|
||||
|
||||
func (rs *REST) Get(ctx api.Context, id string) (runtime.Object, error) {
|
||||
|
@ -89,7 +89,7 @@ func TestRESTCreate(t *testing.T) {
|
||||
if !api.HasObjectMetaSystemFieldValues(&item.event.ObjectMeta) {
|
||||
t.Errorf("storage did not populate object meta field values")
|
||||
}
|
||||
if e, a := item.event, (<-c).Object; !reflect.DeepEqual(e, a) {
|
||||
if e, a := item.event, c; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("diff: %s", util.ObjectDiff(e, a))
|
||||
}
|
||||
// Ensure we implement the interface
|
||||
@ -100,11 +100,10 @@ func TestRESTCreate(t *testing.T) {
|
||||
func TestRESTUpdate(t *testing.T) {
|
||||
_, rest := NewTestREST()
|
||||
eventA := testEvent("foo")
|
||||
c, err := rest.Create(api.NewDefaultContext(), eventA)
|
||||
_, err := rest.Create(api.NewDefaultContext(), eventA)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error %v", err)
|
||||
}
|
||||
<-c
|
||||
got, err := rest.Get(api.NewDefaultContext(), eventA.Name)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error %v", err)
|
||||
@ -113,11 +112,10 @@ func TestRESTUpdate(t *testing.T) {
|
||||
t.Errorf("diff: %s", util.ObjectDiff(e, a))
|
||||
}
|
||||
eventB := testEvent("bar")
|
||||
u, err := rest.Update(api.NewDefaultContext(), eventB)
|
||||
_, _, err = rest.Update(api.NewDefaultContext(), eventB)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error %v", err)
|
||||
}
|
||||
<-u
|
||||
got2, err := rest.Get(api.NewDefaultContext(), eventB.Name)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error %v", err)
|
||||
@ -131,16 +129,15 @@ func TestRESTUpdate(t *testing.T) {
|
||||
func TestRESTDelete(t *testing.T) {
|
||||
_, rest := NewTestREST()
|
||||
eventA := testEvent("foo")
|
||||
c, err := rest.Create(api.NewDefaultContext(), eventA)
|
||||
_, err := rest.Create(api.NewDefaultContext(), eventA)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error %v", err)
|
||||
}
|
||||
<-c
|
||||
c, err = rest.Delete(api.NewDefaultContext(), eventA.Name)
|
||||
c, err := rest.Delete(api.NewDefaultContext(), eventA.Name)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error %v", err)
|
||||
}
|
||||
if stat := (<-c).Object.(*api.Status); stat.Status != api.StatusSuccess {
|
||||
if stat := c.(*api.Status); stat.Status != api.StatusSuccess {
|
||||
t.Errorf("unexpected status: %v", stat)
|
||||
}
|
||||
}
|
||||
@ -148,11 +145,10 @@ func TestRESTDelete(t *testing.T) {
|
||||
func TestRESTGet(t *testing.T) {
|
||||
_, rest := NewTestREST()
|
||||
eventA := testEvent("foo")
|
||||
c, err := rest.Create(api.NewDefaultContext(), eventA)
|
||||
_, err := rest.Create(api.NewDefaultContext(), eventA)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error %v", err)
|
||||
}
|
||||
<-c
|
||||
got, err := rest.Get(api.NewDefaultContext(), eventA.Name)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error %v", err)
|
||||
|
@ -22,7 +22,6 @@ import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
@ -44,7 +43,7 @@ func NewREST(registry generic.Registry) *REST {
|
||||
}
|
||||
|
||||
// Create a LimitRange object
|
||||
func (rs *REST) Create(ctx api.Context, obj runtime.Object) (<-chan apiserver.RESTResult, error) {
|
||||
func (rs *REST) Create(ctx api.Context, obj runtime.Object) (runtime.Object, error) {
|
||||
limitRange, ok := obj.(*api.LimitRange)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid object type")
|
||||
@ -63,29 +62,27 @@ func (rs *REST) Create(ctx api.Context, obj runtime.Object) (<-chan apiserver.RE
|
||||
}
|
||||
api.FillObjectMetaSystemFields(ctx, &limitRange.ObjectMeta)
|
||||
|
||||
return apiserver.MakeAsync(func() (runtime.Object, error) {
|
||||
err := rs.registry.Create(ctx, limitRange.Name, limitRange)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rs.registry.Get(ctx, limitRange.Name)
|
||||
}), nil
|
||||
err := rs.registry.Create(ctx, limitRange.Name, limitRange)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rs.registry.Get(ctx, limitRange.Name)
|
||||
}
|
||||
|
||||
// Update updates a LimitRange object.
|
||||
func (rs *REST) Update(ctx api.Context, obj runtime.Object) (<-chan apiserver.RESTResult, error) {
|
||||
func (rs *REST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
||||
limitRange, ok := obj.(*api.LimitRange)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid object type")
|
||||
return nil, false, fmt.Errorf("invalid object type")
|
||||
}
|
||||
|
||||
if !api.ValidNamespace(ctx, &limitRange.ObjectMeta) {
|
||||
return nil, errors.NewConflict("limitRange", limitRange.Namespace, fmt.Errorf("LimitRange.Namespace does not match the provided context"))
|
||||
return nil, false, errors.NewConflict("limitRange", limitRange.Namespace, fmt.Errorf("LimitRange.Namespace does not match the provided context"))
|
||||
}
|
||||
|
||||
oldObj, err := rs.registry.Get(ctx, limitRange.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
editLimitRange := oldObj.(*api.LimitRange)
|
||||
@ -97,20 +94,18 @@ func (rs *REST) Update(ctx api.Context, obj runtime.Object) (<-chan apiserver.RE
|
||||
editLimitRange.Spec = limitRange.Spec
|
||||
|
||||
if errs := validation.ValidateLimitRange(editLimitRange); len(errs) > 0 {
|
||||
return nil, errors.NewInvalid("limitRange", editLimitRange.Name, errs)
|
||||
return nil, false, errors.NewInvalid("limitRange", editLimitRange.Name, errs)
|
||||
}
|
||||
|
||||
return apiserver.MakeAsync(func() (runtime.Object, error) {
|
||||
err := rs.registry.Update(ctx, editLimitRange.Name, editLimitRange)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rs.registry.Get(ctx, editLimitRange.Name)
|
||||
}), nil
|
||||
if err := rs.registry.Update(ctx, editLimitRange.Name, editLimitRange); err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
out, err := rs.registry.Get(ctx, editLimitRange.Name)
|
||||
return out, false, err
|
||||
}
|
||||
|
||||
// Delete deletes the LimitRange with the specified name
|
||||
func (rs *REST) Delete(ctx api.Context, name string) (<-chan apiserver.RESTResult, error) {
|
||||
func (rs *REST) Delete(ctx api.Context, name string) (runtime.Object, error) {
|
||||
obj, err := rs.registry.Get(ctx, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -119,9 +114,7 @@ func (rs *REST) Delete(ctx api.Context, name string) (<-chan apiserver.RESTResul
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid object type")
|
||||
}
|
||||
return apiserver.MakeAsync(func() (runtime.Object, error) {
|
||||
return &api.Status{Status: api.StatusSuccess}, rs.registry.Delete(ctx, name)
|
||||
}), nil
|
||||
return &api.Status{Status: api.StatusSuccess}, rs.registry.Delete(ctx, name)
|
||||
}
|
||||
|
||||
// Get gets a LimitRange with the specified name
|
||||
|
@ -26,7 +26,6 @@ import (
|
||||
kerrors "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/master/ports"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
@ -49,7 +48,7 @@ var ErrDoesNotExist = errors.New("The requested resource does not exist.")
|
||||
var ErrNotHealty = errors.New("The requested minion is not healthy.")
|
||||
|
||||
// Create satisfies the RESTStorage interface.
|
||||
func (rs *REST) Create(ctx api.Context, obj runtime.Object) (<-chan apiserver.RESTResult, error) {
|
||||
func (rs *REST) Create(ctx api.Context, obj runtime.Object) (runtime.Object, error) {
|
||||
minion, ok := obj.(*api.Node)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("not a minion: %#v", obj)
|
||||
@ -59,17 +58,15 @@ func (rs *REST) Create(ctx api.Context, obj runtime.Object) (<-chan apiserver.RE
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return apiserver.MakeAsync(func() (runtime.Object, error) {
|
||||
if err := rs.registry.CreateMinion(ctx, minion); err != nil {
|
||||
err = rest.CheckGeneratedNameError(rest.Nodes, err, minion)
|
||||
return nil, err
|
||||
}
|
||||
return minion, nil
|
||||
}), nil
|
||||
if err := rs.registry.CreateMinion(ctx, minion); err != nil {
|
||||
err = rest.CheckGeneratedNameError(rest.Nodes, err, minion)
|
||||
return nil, err
|
||||
}
|
||||
return minion, nil
|
||||
}
|
||||
|
||||
// Delete satisfies the RESTStorage interface.
|
||||
func (rs *REST) Delete(ctx api.Context, id string) (<-chan apiserver.RESTResult, error) {
|
||||
func (rs *REST) Delete(ctx api.Context, id string) (runtime.Object, error) {
|
||||
minion, err := rs.registry.GetMinion(ctx, id)
|
||||
if minion == nil {
|
||||
return nil, ErrDoesNotExist
|
||||
@ -77,9 +74,7 @@ func (rs *REST) Delete(ctx api.Context, id string) (<-chan apiserver.RESTResult,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return apiserver.MakeAsync(func() (runtime.Object, error) {
|
||||
return &api.Status{Status: api.StatusSuccess}, rs.registry.DeleteMinion(ctx, id)
|
||||
}), nil
|
||||
return &api.Status{Status: api.StatusSuccess}, rs.registry.DeleteMinion(ctx, id)
|
||||
}
|
||||
|
||||
// Get satisfies the RESTStorage interface.
|
||||
@ -108,10 +103,10 @@ func (*REST) NewList() runtime.Object {
|
||||
}
|
||||
|
||||
// Update satisfies the RESTStorage interface.
|
||||
func (rs *REST) Update(ctx api.Context, obj runtime.Object) (<-chan apiserver.RESTResult, error) {
|
||||
func (rs *REST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
||||
minion, ok := obj.(*api.Node)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("not a minion: %#v", obj)
|
||||
return nil, false, fmt.Errorf("not a minion: %#v", obj)
|
||||
}
|
||||
// This is hacky, but minions don't really have a namespace, but kubectl currently automatically
|
||||
// stuffs one in there. Fix it here temporarily until we fix kubectl
|
||||
@ -123,7 +118,7 @@ func (rs *REST) Update(ctx api.Context, obj runtime.Object) (<-chan apiserver.RE
|
||||
|
||||
oldMinion, err := rs.registry.GetMinion(ctx, minion.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
// This is hacky, but minion HostIP has been moved from spec to status since v1beta2. When updating
|
||||
@ -134,16 +129,14 @@ func (rs *REST) Update(ctx api.Context, obj runtime.Object) (<-chan apiserver.RE
|
||||
}
|
||||
|
||||
if errs := validation.ValidateMinionUpdate(oldMinion, minion); len(errs) > 0 {
|
||||
return nil, kerrors.NewInvalid("minion", minion.Name, errs)
|
||||
return nil, false, kerrors.NewInvalid("minion", minion.Name, errs)
|
||||
}
|
||||
|
||||
return apiserver.MakeAsync(func() (runtime.Object, error) {
|
||||
err := rs.registry.UpdateMinion(ctx, minion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rs.registry.GetMinion(ctx, minion.Name)
|
||||
}), nil
|
||||
if err := rs.registry.UpdateMinion(ctx, minion); err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
out, err := rs.registry.GetMinion(ctx, minion.Name)
|
||||
return out, false, err
|
||||
}
|
||||
|
||||
// Watch returns Minions events via a watch.Interface.
|
||||
|
@ -39,27 +39,25 @@ func TestMinionRegistryREST(t *testing.T) {
|
||||
t.Errorf("has unexpected error: %v", err)
|
||||
}
|
||||
|
||||
c, err := ms.Create(ctx, &api.Node{ObjectMeta: api.ObjectMeta{Name: "baz"}})
|
||||
obj, err := ms.Create(ctx, &api.Node{ObjectMeta: api.ObjectMeta{Name: "baz"}})
|
||||
if err != nil {
|
||||
t.Fatalf("insert failed: %v", err)
|
||||
}
|
||||
obj := <-c
|
||||
if !api.HasObjectMetaSystemFieldValues(&obj.Object.(*api.Node).ObjectMeta) {
|
||||
if !api.HasObjectMetaSystemFieldValues(&obj.(*api.Node).ObjectMeta) {
|
||||
t.Errorf("storage did not populate object meta field values")
|
||||
}
|
||||
if m, ok := obj.Object.(*api.Node); !ok || m.Name != "baz" {
|
||||
if m, ok := obj.(*api.Node); !ok || m.Name != "baz" {
|
||||
t.Errorf("insert return value was weird: %#v", obj)
|
||||
}
|
||||
if obj, err := ms.Get(ctx, "baz"); err != nil || obj.(*api.Node).Name != "baz" {
|
||||
t.Errorf("insert didn't actually insert")
|
||||
}
|
||||
|
||||
c, err = ms.Delete(ctx, "bar")
|
||||
obj, err = ms.Delete(ctx, "bar")
|
||||
if err != nil {
|
||||
t.Fatalf("delete failed")
|
||||
}
|
||||
obj = <-c
|
||||
if s, ok := obj.Object.(*api.Status); !ok || s.Status != api.StatusSuccess {
|
||||
if s, ok := obj.(*api.Status); !ok || s.Status != api.StatusSuccess {
|
||||
t.Errorf("delete return value was weird: %#v", obj)
|
||||
}
|
||||
if _, err := ms.Get(ctx, "bar"); !errors.IsNotFound(err) {
|
||||
@ -103,7 +101,7 @@ func TestMinionRegistryValidUpdate(t *testing.T) {
|
||||
"foo": "bar",
|
||||
"baz": "home",
|
||||
}
|
||||
if _, err = storage.Update(ctx, minion); err != nil {
|
||||
if _, _, err = storage.Update(ctx, minion); err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
@ -136,7 +134,7 @@ func TestMinionRegistryValidatesCreate(t *testing.T) {
|
||||
for _, failureCase := range failureCases {
|
||||
c, err := storage.Create(ctx, &failureCase)
|
||||
if c != nil {
|
||||
t.Errorf("Expected nil channel")
|
||||
t.Errorf("Expected nil object")
|
||||
}
|
||||
if !errors.IsInvalid(err) {
|
||||
t.Errorf("Expected to get an invalid resource error, got %v", err)
|
||||
|
@ -23,7 +23,6 @@ import (
|
||||
kerrors "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
@ -44,48 +43,44 @@ func NewREST(registry generic.Registry) *REST {
|
||||
}
|
||||
|
||||
// Create creates a Namespace object
|
||||
func (rs *REST) Create(ctx api.Context, obj runtime.Object) (<-chan apiserver.RESTResult, error) {
|
||||
func (rs *REST) Create(ctx api.Context, obj runtime.Object) (runtime.Object, error) {
|
||||
namespace := obj.(*api.Namespace)
|
||||
if err := rest.BeforeCreate(rest.Namespaces, ctx, obj); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return apiserver.MakeAsync(func() (runtime.Object, error) {
|
||||
if err := rs.registry.Create(ctx, namespace.Name, namespace); err != nil {
|
||||
err = rest.CheckGeneratedNameError(rest.Namespaces, err, namespace)
|
||||
return nil, err
|
||||
}
|
||||
return rs.registry.Get(ctx, namespace.Name)
|
||||
}), nil
|
||||
if err := rs.registry.Create(ctx, namespace.Name, namespace); err != nil {
|
||||
err = rest.CheckGeneratedNameError(rest.Namespaces, err, namespace)
|
||||
return nil, err
|
||||
}
|
||||
return rs.registry.Get(ctx, namespace.Name)
|
||||
}
|
||||
|
||||
// Update updates a Namespace object.
|
||||
func (rs *REST) Update(ctx api.Context, obj runtime.Object) (<-chan apiserver.RESTResult, error) {
|
||||
func (rs *REST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
||||
namespace, ok := obj.(*api.Namespace)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("not a namespace: %#v", obj)
|
||||
return nil, false, fmt.Errorf("not a namespace: %#v", obj)
|
||||
}
|
||||
|
||||
oldObj, err := rs.registry.Get(ctx, namespace.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
oldNamespace := oldObj.(*api.Namespace)
|
||||
if errs := validation.ValidateNamespaceUpdate(oldNamespace, namespace); len(errs) > 0 {
|
||||
return nil, kerrors.NewInvalid("namespace", namespace.Name, errs)
|
||||
return nil, false, kerrors.NewInvalid("namespace", namespace.Name, errs)
|
||||
}
|
||||
|
||||
return apiserver.MakeAsync(func() (runtime.Object, error) {
|
||||
err := rs.registry.Update(ctx, oldNamespace.Name, oldNamespace)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rs.registry.Get(ctx, oldNamespace.Name)
|
||||
}), nil
|
||||
if err := rs.registry.Update(ctx, oldNamespace.Name, oldNamespace); err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
out, err := rs.registry.Get(ctx, oldNamespace.Name)
|
||||
return out, false, err
|
||||
}
|
||||
|
||||
// Delete deletes the Namespace with the specified name
|
||||
func (rs *REST) Delete(ctx api.Context, id string) (<-chan apiserver.RESTResult, error) {
|
||||
func (rs *REST) Delete(ctx api.Context, id string) (runtime.Object, error) {
|
||||
obj, err := rs.registry.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -94,10 +89,7 @@ func (rs *REST) Delete(ctx api.Context, id string) (<-chan apiserver.RESTResult,
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid object type")
|
||||
}
|
||||
|
||||
return apiserver.MakeAsync(func() (runtime.Object, error) {
|
||||
return &api.Status{Status: api.StatusSuccess}, rs.registry.Delete(ctx, id)
|
||||
}), nil
|
||||
return &api.Status{Status: api.StatusSuccess}, rs.registry.Delete(ctx, id)
|
||||
}
|
||||
|
||||
func (rs *REST) Get(ctx api.Context, id string) (runtime.Object, error) {
|
||||
|
@ -78,7 +78,7 @@ func TestRESTCreate(t *testing.T) {
|
||||
if !api.HasObjectMetaSystemFieldValues(&item.namespace.ObjectMeta) {
|
||||
t.Errorf("storage did not populate object meta field values")
|
||||
}
|
||||
if e, a := item.namespace, (<-c).Object; !reflect.DeepEqual(e, a) {
|
||||
if e, a := item.namespace, c; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("diff: %s", util.ObjectDiff(e, a))
|
||||
}
|
||||
// Ensure we implement the interface
|
||||
@ -89,11 +89,10 @@ func TestRESTCreate(t *testing.T) {
|
||||
func TestRESTUpdate(t *testing.T) {
|
||||
_, rest := NewTestREST()
|
||||
namespaceA := testNamespace("foo")
|
||||
c, err := rest.Create(api.NewDefaultContext(), namespaceA)
|
||||
_, err := rest.Create(api.NewDefaultContext(), namespaceA)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error %v", err)
|
||||
}
|
||||
<-c
|
||||
got, err := rest.Get(api.NewDefaultContext(), namespaceA.Name)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error %v", err)
|
||||
@ -102,11 +101,10 @@ func TestRESTUpdate(t *testing.T) {
|
||||
t.Errorf("diff: %s", util.ObjectDiff(e, a))
|
||||
}
|
||||
namespaceB := testNamespace("foo")
|
||||
u, err := rest.Update(api.NewDefaultContext(), namespaceB)
|
||||
_, _, err = rest.Update(api.NewDefaultContext(), namespaceB)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error %v", err)
|
||||
}
|
||||
<-u
|
||||
got2, err := rest.Get(api.NewDefaultContext(), namespaceB.Name)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error %v", err)
|
||||
@ -120,16 +118,15 @@ func TestRESTUpdate(t *testing.T) {
|
||||
func TestRESTDelete(t *testing.T) {
|
||||
_, rest := NewTestREST()
|
||||
namespaceA := testNamespace("foo")
|
||||
c, err := rest.Create(api.NewContext(), namespaceA)
|
||||
_, err := rest.Create(api.NewContext(), namespaceA)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error %v", err)
|
||||
}
|
||||
<-c
|
||||
c, err = rest.Delete(api.NewContext(), namespaceA.Name)
|
||||
c, err := rest.Delete(api.NewContext(), namespaceA.Name)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error %v", err)
|
||||
}
|
||||
if stat := (<-c).Object.(*api.Status); stat.Status != api.StatusSuccess {
|
||||
if stat := c.(*api.Status); stat.Status != api.StatusSuccess {
|
||||
t.Errorf("unexpected status: %v", stat)
|
||||
}
|
||||
}
|
||||
@ -137,11 +134,10 @@ func TestRESTDelete(t *testing.T) {
|
||||
func TestRESTGet(t *testing.T) {
|
||||
_, rest := NewTestREST()
|
||||
namespaceA := testNamespace("foo")
|
||||
c, err := rest.Create(api.NewContext(), namespaceA)
|
||||
_, err := rest.Create(api.NewContext(), namespaceA)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error %v", err)
|
||||
}
|
||||
<-c
|
||||
got, err := rest.Get(api.NewContext(), namespaceA.Name)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error %v", err)
|
||||
|
@ -25,7 +25,6 @@ import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||
@ -55,32 +54,28 @@ func NewREST(config *RESTConfig) *REST {
|
||||
}
|
||||
}
|
||||
|
||||
func (rs *REST) Create(ctx api.Context, obj runtime.Object) (<-chan apiserver.RESTResult, error) {
|
||||
func (rs *REST) Create(ctx api.Context, obj runtime.Object) (runtime.Object, error) {
|
||||
pod := obj.(*api.Pod)
|
||||
|
||||
if err := rest.BeforeCreate(rest.Pods, ctx, obj); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return apiserver.MakeAsync(func() (runtime.Object, error) {
|
||||
if err := rs.registry.CreatePod(ctx, pod); err != nil {
|
||||
err = rest.CheckGeneratedNameError(rest.Pods, err, pod)
|
||||
return nil, err
|
||||
}
|
||||
return rs.registry.GetPod(ctx, pod.Name)
|
||||
}), nil
|
||||
if err := rs.registry.CreatePod(ctx, pod); err != nil {
|
||||
err = rest.CheckGeneratedNameError(rest.Pods, err, pod)
|
||||
return nil, err
|
||||
}
|
||||
return rs.registry.GetPod(ctx, pod.Name)
|
||||
}
|
||||
|
||||
func (rs *REST) Delete(ctx api.Context, id string) (<-chan apiserver.RESTResult, error) {
|
||||
return apiserver.MakeAsync(func() (runtime.Object, error) {
|
||||
namespace, found := api.NamespaceFrom(ctx)
|
||||
if !found {
|
||||
return &api.Status{Status: api.StatusFailure}, nil
|
||||
}
|
||||
rs.podCache.ClearPodStatus(namespace, id)
|
||||
func (rs *REST) Delete(ctx api.Context, id string) (runtime.Object, error) {
|
||||
namespace, found := api.NamespaceFrom(ctx)
|
||||
if !found {
|
||||
return &api.Status{Status: api.StatusFailure}, nil
|
||||
}
|
||||
rs.podCache.ClearPodStatus(namespace, id)
|
||||
|
||||
return &api.Status{Status: api.StatusSuccess}, rs.registry.DeletePod(ctx, id)
|
||||
}), nil
|
||||
return &api.Status{Status: api.StatusSuccess}, rs.registry.DeletePod(ctx, id)
|
||||
}
|
||||
|
||||
func (rs *REST) Get(ctx api.Context, id string) (runtime.Object, error) {
|
||||
@ -167,20 +162,19 @@ func (*REST) NewList() runtime.Object {
|
||||
return &api.PodList{}
|
||||
}
|
||||
|
||||
func (rs *REST) Update(ctx api.Context, obj runtime.Object) (<-chan apiserver.RESTResult, error) {
|
||||
func (rs *REST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
||||
pod := obj.(*api.Pod)
|
||||
if !api.ValidNamespace(ctx, &pod.ObjectMeta) {
|
||||
return nil, errors.NewConflict("pod", pod.Namespace, fmt.Errorf("Pod.Namespace does not match the provided context"))
|
||||
return nil, false, errors.NewConflict("pod", pod.Namespace, fmt.Errorf("Pod.Namespace does not match the provided context"))
|
||||
}
|
||||
if errs := validation.ValidatePod(pod); len(errs) > 0 {
|
||||
return nil, errors.NewInvalid("pod", pod.Name, errs)
|
||||
return nil, false, errors.NewInvalid("pod", pod.Name, errs)
|
||||
}
|
||||
return apiserver.MakeAsync(func() (runtime.Object, error) {
|
||||
if err := rs.registry.UpdatePod(ctx, pod); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rs.registry.GetPod(ctx, pod.Name)
|
||||
}), nil
|
||||
if err := rs.registry.UpdatePod(ctx, pod); err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
out, err := rs.registry.GetPod(ctx, pod.Name)
|
||||
return out, false, err
|
||||
}
|
||||
|
||||
// ResourceLocation returns a URL to which one can send traffic for the specified pod.
|
||||
|
@ -21,7 +21,6 @@ import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
|
||||
@ -31,6 +30,7 @@ import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
)
|
||||
|
||||
@ -55,9 +55,8 @@ func (f *fakeCache) ClearPodStatus(namespace, name string) {
|
||||
f.clearedName = name
|
||||
}
|
||||
|
||||
func expectApiStatusError(t *testing.T, ch <-chan apiserver.RESTResult, msg string) {
|
||||
out := <-ch
|
||||
status, ok := out.Object.(*api.Status)
|
||||
func expectApiStatusError(t *testing.T, out runtime.Object, msg string) {
|
||||
status, ok := out.(*api.Status)
|
||||
if !ok {
|
||||
t.Errorf("Expected an api.Status object, was %#v", out)
|
||||
return
|
||||
@ -67,9 +66,8 @@ func expectApiStatusError(t *testing.T, ch <-chan apiserver.RESTResult, msg stri
|
||||
}
|
||||
}
|
||||
|
||||
func expectPod(t *testing.T, ch <-chan apiserver.RESTResult) (*api.Pod, bool) {
|
||||
out := <-ch
|
||||
pod, ok := out.Object.(*api.Pod)
|
||||
func expectPod(t *testing.T, out runtime.Object) (*api.Pod, bool) {
|
||||
pod, ok := out.(*api.Pod)
|
||||
if !ok || pod == nil {
|
||||
t.Errorf("Expected an api.Pod object, was %#v", out)
|
||||
return nil, false
|
||||
@ -94,11 +92,10 @@ func TestCreatePodRegistryError(t *testing.T) {
|
||||
},
|
||||
}
|
||||
ctx := api.NewDefaultContext()
|
||||
ch, err := storage.Create(ctx, pod)
|
||||
if err != nil {
|
||||
_, err := storage.Create(ctx, pod)
|
||||
if err != podRegistry.Err {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
expectApiStatusError(t, ch, podRegistry.Err.Error())
|
||||
}
|
||||
|
||||
func TestCreatePodSetsIds(t *testing.T) {
|
||||
@ -118,11 +115,10 @@ func TestCreatePodSetsIds(t *testing.T) {
|
||||
},
|
||||
}
|
||||
ctx := api.NewDefaultContext()
|
||||
ch, err := storage.Create(ctx, pod)
|
||||
if err != nil {
|
||||
_, err := storage.Create(ctx, pod)
|
||||
if err != podRegistry.Err {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
expectApiStatusError(t, ch, podRegistry.Err.Error())
|
||||
|
||||
if len(podRegistry.Pod.Name) == 0 {
|
||||
t.Errorf("Expected pod ID to be set, Got %#v", pod)
|
||||
@ -149,11 +145,10 @@ func TestCreatePodSetsUID(t *testing.T) {
|
||||
},
|
||||
}
|
||||
ctx := api.NewDefaultContext()
|
||||
ch, err := storage.Create(ctx, pod)
|
||||
if err != nil {
|
||||
_, err := storage.Create(ctx, pod)
|
||||
if err != podRegistry.Err {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
expectApiStatusError(t, ch, podRegistry.Err.Error())
|
||||
|
||||
if len(podRegistry.Pod.UID) == 0 {
|
||||
t.Errorf("Expected pod UID to be set, Got %#v", pod)
|
||||
@ -471,15 +466,12 @@ func TestCreatePod(t *testing.T) {
|
||||
}
|
||||
pod.Name = "foo"
|
||||
ctx := api.NewDefaultContext()
|
||||
channel, err := storage.Create(ctx, pod)
|
||||
obj, err := storage.Create(ctx, pod)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
select {
|
||||
case <-channel:
|
||||
// Do nothing, this is expected.
|
||||
case <-time.After(time.Millisecond * 100):
|
||||
t.Error("Unexpected timeout on async channel")
|
||||
if obj == nil {
|
||||
t.Fatalf("unexpected object: %#v", obj)
|
||||
}
|
||||
if !api.HasObjectMetaSystemFieldValues(&podRegistry.Pod.ObjectMeta) {
|
||||
t.Errorf("Expected ObjectMeta field values were populated")
|
||||
@ -520,9 +512,9 @@ func TestUpdatePodWithConflictingNamespace(t *testing.T) {
|
||||
}
|
||||
|
||||
ctx := api.NewDefaultContext()
|
||||
channel, err := storage.Update(ctx, pod)
|
||||
if channel != nil {
|
||||
t.Error("Expected a nil channel, but we got a value")
|
||||
obj, created, err := storage.Update(ctx, pod)
|
||||
if obj != nil || created {
|
||||
t.Error("Expected a nil channel, but we got a value or created")
|
||||
}
|
||||
if err == nil {
|
||||
t.Errorf("Expected an error, but we didn't get one")
|
||||
@ -648,19 +640,12 @@ func TestDeletePod(t *testing.T) {
|
||||
podCache: fakeCache,
|
||||
}
|
||||
ctx := api.NewDefaultContext()
|
||||
channel, err := storage.Delete(ctx, "foo")
|
||||
result, err := storage.Delete(ctx, "foo")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
var result apiserver.RESTResult
|
||||
select {
|
||||
case result = <-channel:
|
||||
// Do nothing, this is expected.
|
||||
case <-time.After(time.Millisecond * 100):
|
||||
t.Error("Unexpected timeout on async channel")
|
||||
}
|
||||
if fakeCache.clearedNamespace != "default" || fakeCache.clearedName != "foo" {
|
||||
t.Errorf("Unexpeceted cache delete: %s %s %#v", fakeCache.clearedName, fakeCache.clearedNamespace, result.Object)
|
||||
t.Errorf("Unexpeceted cache delete: %s %s %#v", fakeCache.clearedName, fakeCache.clearedNamespace, result)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,6 @@ import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
@ -44,7 +43,7 @@ func NewREST(registry generic.Registry) *REST {
|
||||
}
|
||||
|
||||
// Create a ResourceQuota object
|
||||
func (rs *REST) Create(ctx api.Context, obj runtime.Object) (<-chan apiserver.RESTResult, error) {
|
||||
func (rs *REST) Create(ctx api.Context, obj runtime.Object) (runtime.Object, error) {
|
||||
resourceQuota, ok := obj.(*api.ResourceQuota)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid object type")
|
||||
@ -66,29 +65,27 @@ func (rs *REST) Create(ctx api.Context, obj runtime.Object) (<-chan apiserver.RE
|
||||
}
|
||||
api.FillObjectMetaSystemFields(ctx, &resourceQuota.ObjectMeta)
|
||||
|
||||
return apiserver.MakeAsync(func() (runtime.Object, error) {
|
||||
err := rs.registry.Create(ctx, resourceQuota.Name, resourceQuota)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rs.registry.Get(ctx, resourceQuota.Name)
|
||||
}), nil
|
||||
err := rs.registry.Create(ctx, resourceQuota.Name, resourceQuota)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rs.registry.Get(ctx, resourceQuota.Name)
|
||||
}
|
||||
|
||||
// Update updates a ResourceQuota object.
|
||||
func (rs *REST) Update(ctx api.Context, obj runtime.Object) (<-chan apiserver.RESTResult, error) {
|
||||
func (rs *REST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
||||
resourceQuota, ok := obj.(*api.ResourceQuota)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid object type")
|
||||
return nil, false, fmt.Errorf("invalid object type")
|
||||
}
|
||||
|
||||
if !api.ValidNamespace(ctx, &resourceQuota.ObjectMeta) {
|
||||
return nil, errors.NewConflict("resourceQuota", resourceQuota.Namespace, fmt.Errorf("ResourceQuota.Namespace does not match the provided context"))
|
||||
return nil, false, errors.NewConflict("resourceQuota", resourceQuota.Namespace, fmt.Errorf("ResourceQuota.Namespace does not match the provided context"))
|
||||
}
|
||||
|
||||
oldObj, err := rs.registry.Get(ctx, resourceQuota.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
editResourceQuota := oldObj.(*api.ResourceQuota)
|
||||
@ -100,20 +97,18 @@ func (rs *REST) Update(ctx api.Context, obj runtime.Object) (<-chan apiserver.RE
|
||||
editResourceQuota.Spec = resourceQuota.Spec
|
||||
|
||||
if errs := validation.ValidateResourceQuota(editResourceQuota); len(errs) > 0 {
|
||||
return nil, errors.NewInvalid("resourceQuota", editResourceQuota.Name, errs)
|
||||
return nil, false, errors.NewInvalid("resourceQuota", editResourceQuota.Name, errs)
|
||||
}
|
||||
|
||||
return apiserver.MakeAsync(func() (runtime.Object, error) {
|
||||
err := rs.registry.Update(ctx, editResourceQuota.Name, editResourceQuota)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rs.registry.Get(ctx, editResourceQuota.Name)
|
||||
}), nil
|
||||
if err := rs.registry.Update(ctx, editResourceQuota.Name, editResourceQuota); err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
out, err := rs.registry.Get(ctx, editResourceQuota.Name)
|
||||
return out, false, err
|
||||
}
|
||||
|
||||
// Delete deletes the ResourceQuota with the specified name
|
||||
func (rs *REST) Delete(ctx api.Context, name string) (<-chan apiserver.RESTResult, error) {
|
||||
func (rs *REST) Delete(ctx api.Context, name string) (runtime.Object, error) {
|
||||
obj, err := rs.registry.Get(ctx, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -122,9 +117,7 @@ func (rs *REST) Delete(ctx api.Context, name string) (<-chan apiserver.RESTResul
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid object type")
|
||||
}
|
||||
return apiserver.MakeAsync(func() (runtime.Object, error) {
|
||||
return &api.Status{Status: api.StatusSuccess}, rs.registry.Delete(ctx, name)
|
||||
}), nil
|
||||
return &api.Status{Status: api.StatusSuccess}, rs.registry.Delete(ctx, name)
|
||||
}
|
||||
|
||||
// Get gets a ResourceQuota with the specified name
|
||||
|
@ -20,7 +20,6 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
@ -42,15 +41,13 @@ func (*REST) New() runtime.Object {
|
||||
}
|
||||
|
||||
// Create takes the incoming ResourceQuotaUsage and applies the latest status atomically to a ResourceQuota
|
||||
func (b *REST) Create(ctx api.Context, obj runtime.Object) (<-chan apiserver.RESTResult, error) {
|
||||
func (b *REST) Create(ctx api.Context, obj runtime.Object) (runtime.Object, error) {
|
||||
resourceQuotaUsage, ok := obj.(*api.ResourceQuotaUsage)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("incorrect type: %#v", obj)
|
||||
}
|
||||
return apiserver.MakeAsync(func() (runtime.Object, error) {
|
||||
if err := b.registry.ApplyStatus(ctx, resourceQuotaUsage); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &api.Status{Status: api.StatusSuccess}, nil
|
||||
}), nil
|
||||
if err := b.registry.ApplyStatus(ctx, resourceQuotaUsage); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &api.Status{Status: api.StatusSuccess}, nil
|
||||
}
|
||||
|
@ -25,7 +25,6 @@ import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/minion"
|
||||
@ -80,7 +79,7 @@ func reloadIPsFromStorage(ipa *ipAllocator, registry Registry) {
|
||||
}
|
||||
}
|
||||
|
||||
func (rs *REST) Create(ctx api.Context, obj runtime.Object) (<-chan apiserver.RESTResult, error) {
|
||||
func (rs *REST) Create(ctx api.Context, obj runtime.Object) (runtime.Object, error) {
|
||||
service := obj.(*api.Service)
|
||||
|
||||
if err := rest.BeforeCreate(rest.Services, ctx, obj); err != nil {
|
||||
@ -102,61 +101,59 @@ func (rs *REST) Create(ctx api.Context, obj runtime.Object) (<-chan apiserver.RE
|
||||
}
|
||||
}
|
||||
|
||||
return apiserver.MakeAsync(func() (runtime.Object, error) {
|
||||
// TODO: Move this to post-creation rectification loop, so that we make/remove external load balancers
|
||||
// correctly no matter what http operations happen.
|
||||
if service.Spec.CreateExternalLoadBalancer {
|
||||
if rs.cloud == nil {
|
||||
return nil, fmt.Errorf("requested an external service, but no cloud provider supplied.")
|
||||
}
|
||||
if service.Spec.Protocol != api.ProtocolTCP {
|
||||
// TODO: Support UDP here too.
|
||||
return nil, fmt.Errorf("external load balancers for non TCP services are not currently supported.")
|
||||
}
|
||||
balancer, ok := rs.cloud.TCPLoadBalancer()
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("the cloud provider does not support external TCP load balancers.")
|
||||
}
|
||||
zones, ok := rs.cloud.Zones()
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("the cloud provider does not support zone enumeration.")
|
||||
}
|
||||
hosts, err := rs.machines.ListMinions(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
zone, err := zones.GetZone()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// TODO: We should be able to rely on valid input, and not do defaulting here.
|
||||
var affinityType api.AffinityType = service.Spec.SessionAffinity
|
||||
if affinityType == "" {
|
||||
affinityType = api.AffinityTypeNone
|
||||
}
|
||||
if len(service.Spec.PublicIPs) > 0 {
|
||||
for _, publicIP := range service.Spec.PublicIPs {
|
||||
_, err = balancer.CreateTCPLoadBalancer(service.Name, zone.Region, net.ParseIP(publicIP), service.Spec.Port, hostsFromMinionList(hosts), affinityType)
|
||||
if err != nil {
|
||||
// TODO: have to roll-back any successful calls.
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ip, err := balancer.CreateTCPLoadBalancer(service.Name, zone.Region, nil, service.Spec.Port, hostsFromMinionList(hosts), affinityType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
service.Spec.PublicIPs = []string{ip.String()}
|
||||
}
|
||||
// TODO: Move this to post-creation rectification loop, so that we make/remove external load balancers
|
||||
// correctly no matter what http operations happen.
|
||||
if service.Spec.CreateExternalLoadBalancer {
|
||||
if rs.cloud == nil {
|
||||
return nil, fmt.Errorf("requested an external service, but no cloud provider supplied.")
|
||||
}
|
||||
|
||||
if err := rs.registry.CreateService(ctx, service); err != nil {
|
||||
err = rest.CheckGeneratedNameError(rest.Services, err, service)
|
||||
if service.Spec.Protocol != api.ProtocolTCP {
|
||||
// TODO: Support UDP here too.
|
||||
return nil, fmt.Errorf("external load balancers for non TCP services are not currently supported.")
|
||||
}
|
||||
balancer, ok := rs.cloud.TCPLoadBalancer()
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("the cloud provider does not support external TCP load balancers.")
|
||||
}
|
||||
zones, ok := rs.cloud.Zones()
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("the cloud provider does not support zone enumeration.")
|
||||
}
|
||||
hosts, err := rs.machines.ListMinions(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rs.registry.GetService(ctx, service.Name)
|
||||
}), nil
|
||||
zone, err := zones.GetZone()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// TODO: We should be able to rely on valid input, and not do defaulting here.
|
||||
var affinityType api.AffinityType = service.Spec.SessionAffinity
|
||||
if affinityType == "" {
|
||||
affinityType = api.AffinityTypeNone
|
||||
}
|
||||
if len(service.Spec.PublicIPs) > 0 {
|
||||
for _, publicIP := range service.Spec.PublicIPs {
|
||||
_, err = balancer.CreateTCPLoadBalancer(service.Name, zone.Region, net.ParseIP(publicIP), service.Spec.Port, hostsFromMinionList(hosts), affinityType)
|
||||
if err != nil {
|
||||
// TODO: have to roll-back any successful calls.
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ip, err := balancer.CreateTCPLoadBalancer(service.Name, zone.Region, nil, service.Spec.Port, hostsFromMinionList(hosts), affinityType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
service.Spec.PublicIPs = []string{ip.String()}
|
||||
}
|
||||
}
|
||||
|
||||
if err := rs.registry.CreateService(ctx, service); err != nil {
|
||||
err = rest.CheckGeneratedNameError(rest.Services, err, service)
|
||||
return nil, err
|
||||
}
|
||||
return rs.registry.GetService(ctx, service.Name)
|
||||
}
|
||||
|
||||
func hostsFromMinionList(list *api.NodeList) []string {
|
||||
@ -167,16 +164,14 @@ func hostsFromMinionList(list *api.NodeList) []string {
|
||||
return result
|
||||
}
|
||||
|
||||
func (rs *REST) Delete(ctx api.Context, id string) (<-chan apiserver.RESTResult, error) {
|
||||
func (rs *REST) Delete(ctx api.Context, id string) (runtime.Object, error) {
|
||||
service, err := rs.registry.GetService(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rs.portalMgr.Release(net.ParseIP(service.Spec.PortalIP))
|
||||
return apiserver.MakeAsync(func() (runtime.Object, error) {
|
||||
rs.deleteExternalLoadBalancer(service)
|
||||
return &api.Status{Status: api.StatusSuccess}, rs.registry.DeleteService(ctx, id)
|
||||
}), nil
|
||||
rs.deleteExternalLoadBalancer(service)
|
||||
return &api.Status{Status: api.StatusSuccess}, rs.registry.DeleteService(ctx, id)
|
||||
}
|
||||
|
||||
func (rs *REST) Get(ctx api.Context, id string) (runtime.Object, error) {
|
||||
@ -217,30 +212,29 @@ func (*REST) NewList() runtime.Object {
|
||||
return &api.Service{}
|
||||
}
|
||||
|
||||
func (rs *REST) Update(ctx api.Context, obj runtime.Object) (<-chan apiserver.RESTResult, error) {
|
||||
func (rs *REST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
||||
service := obj.(*api.Service)
|
||||
if !api.ValidNamespace(ctx, &service.ObjectMeta) {
|
||||
return nil, errors.NewConflict("service", service.Namespace, fmt.Errorf("Service.Namespace does not match the provided context"))
|
||||
return nil, false, errors.NewConflict("service", service.Namespace, fmt.Errorf("Service.Namespace does not match the provided context"))
|
||||
}
|
||||
|
||||
oldService, err := rs.registry.GetService(ctx, service.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
// Copy over non-user fields
|
||||
// TODO: make this a merge function
|
||||
if errs := validation.ValidateServiceUpdate(oldService, service); len(errs) > 0 {
|
||||
return nil, errors.NewInvalid("service", service.Name, errs)
|
||||
return nil, false, errors.NewInvalid("service", service.Name, errs)
|
||||
}
|
||||
return apiserver.MakeAsync(func() (runtime.Object, error) {
|
||||
// TODO: check to see if external load balancer status changed
|
||||
err = rs.registry.UpdateService(ctx, service)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rs.registry.GetService(ctx, service.Name)
|
||||
}), nil
|
||||
// TODO: check to see if external load balancer status changed
|
||||
err = rs.registry.UpdateService(ctx, service)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
out, err := rs.registry.GetService(ctx, service.Name)
|
||||
return out, false, err
|
||||
}
|
||||
|
||||
// ResourceLocation returns a URL to which one can send traffic for the specified service.
|
||||
|
@ -56,9 +56,8 @@ func TestServiceRegistryCreate(t *testing.T) {
|
||||
},
|
||||
}
|
||||
ctx := api.NewDefaultContext()
|
||||
c, _ := storage.Create(ctx, svc)
|
||||
created_svc := <-c
|
||||
created_service := created_svc.Object.(*api.Service)
|
||||
created_svc, _ := storage.Create(ctx, svc)
|
||||
created_service := created_svc.(*api.Service)
|
||||
if !api.HasObjectMetaSystemFieldValues(&created_service.ObjectMeta) {
|
||||
t.Errorf("storage did not populate object meta field values")
|
||||
}
|
||||
@ -109,7 +108,7 @@ func TestServiceStorageValidatesCreate(t *testing.T) {
|
||||
for _, failureCase := range failureCases {
|
||||
c, err := storage.Create(ctx, &failureCase)
|
||||
if c != nil {
|
||||
t.Errorf("Expected nil channel")
|
||||
t.Errorf("Expected nil object")
|
||||
}
|
||||
if !errors.IsInvalid(err) {
|
||||
t.Errorf("Expected to get an invalid resource error, got %v", err)
|
||||
@ -129,7 +128,7 @@ func TestServiceRegistryUpdate(t *testing.T) {
|
||||
},
|
||||
})
|
||||
storage := NewREST(registry, nil, nil, makeIPNet(t))
|
||||
c, err := storage.Update(ctx, &api.Service{
|
||||
updated_svc, created, err := storage.Update(ctx, &api.Service{
|
||||
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||
Spec: api.ServiceSpec{
|
||||
Port: 6502,
|
||||
@ -141,11 +140,13 @@ func TestServiceRegistryUpdate(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error: %v", err)
|
||||
}
|
||||
if c == nil {
|
||||
t.Errorf("Expected non-nil channel")
|
||||
if updated_svc == nil {
|
||||
t.Errorf("Expected non-nil object")
|
||||
}
|
||||
updated_svc := <-c
|
||||
updated_service := updated_svc.Object.(*api.Service)
|
||||
if created {
|
||||
t.Errorf("expected not created")
|
||||
}
|
||||
updated_service := updated_svc.(*api.Service)
|
||||
if updated_service.Name != "foo" {
|
||||
t.Errorf("Expected foo, but got %v", updated_service.Name)
|
||||
}
|
||||
@ -186,9 +187,9 @@ func TestServiceStorageValidatesUpdate(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, failureCase := range failureCases {
|
||||
c, err := storage.Update(ctx, &failureCase)
|
||||
if c != nil {
|
||||
t.Errorf("Expected nil channel")
|
||||
c, created, err := storage.Update(ctx, &failureCase)
|
||||
if c != nil || created {
|
||||
t.Errorf("Expected nil object or created false")
|
||||
}
|
||||
if !errors.IsInvalid(err) {
|
||||
t.Errorf("Expected to get an invalid resource error, got %v", err)
|
||||
@ -212,8 +213,7 @@ func TestServiceRegistryExternalService(t *testing.T) {
|
||||
SessionAffinity: api.AffinityTypeNone,
|
||||
},
|
||||
}
|
||||
c, _ := storage.Create(ctx, svc)
|
||||
<-c
|
||||
storage.Create(ctx, svc)
|
||||
if len(fakeCloud.Calls) != 2 || fakeCloud.Calls[0] != "get-zone" || fakeCloud.Calls[1] != "create" {
|
||||
t.Errorf("Unexpected call(s): %#v", fakeCloud.Calls)
|
||||
}
|
||||
@ -244,8 +244,7 @@ func TestServiceRegistryExternalServiceError(t *testing.T) {
|
||||
},
|
||||
}
|
||||
ctx := api.NewDefaultContext()
|
||||
c, _ := storage.Create(ctx, svc)
|
||||
<-c
|
||||
storage.Create(ctx, svc)
|
||||
if len(fakeCloud.Calls) != 1 || fakeCloud.Calls[0] != "get-zone" {
|
||||
t.Errorf("Unexpected call(s): %#v", fakeCloud.Calls)
|
||||
}
|
||||
@ -269,8 +268,7 @@ func TestServiceRegistryDelete(t *testing.T) {
|
||||
},
|
||||
}
|
||||
registry.CreateService(ctx, svc)
|
||||
c, _ := storage.Delete(ctx, svc.Name)
|
||||
<-c
|
||||
storage.Delete(ctx, svc.Name)
|
||||
if len(fakeCloud.Calls) != 0 {
|
||||
t.Errorf("Unexpected call(s): %#v", fakeCloud.Calls)
|
||||
}
|
||||
@ -295,8 +293,7 @@ func TestServiceRegistryDeleteExternal(t *testing.T) {
|
||||
},
|
||||
}
|
||||
registry.CreateService(ctx, svc)
|
||||
c, _ := storage.Delete(ctx, svc.Name)
|
||||
<-c
|
||||
storage.Delete(ctx, svc.Name)
|
||||
if len(fakeCloud.Calls) != 2 || fakeCloud.Calls[0] != "get-zone" || fakeCloud.Calls[1] != "delete" {
|
||||
t.Errorf("Unexpected call(s): %#v", fakeCloud.Calls)
|
||||
}
|
||||
@ -413,9 +410,8 @@ func TestServiceRegistryIPAllocation(t *testing.T) {
|
||||
},
|
||||
}
|
||||
ctx := api.NewDefaultContext()
|
||||
c1, _ := rest.Create(ctx, svc1)
|
||||
created_svc1 := <-c1
|
||||
created_service_1 := created_svc1.Object.(*api.Service)
|
||||
created_svc1, _ := rest.Create(ctx, svc1)
|
||||
created_service_1 := created_svc1.(*api.Service)
|
||||
if created_service_1.Name != "foo" {
|
||||
t.Errorf("Expected foo, but got %v", created_service_1.Name)
|
||||
}
|
||||
@ -432,9 +428,8 @@ func TestServiceRegistryIPAllocation(t *testing.T) {
|
||||
SessionAffinity: api.AffinityTypeNone,
|
||||
}}
|
||||
ctx = api.NewDefaultContext()
|
||||
c2, _ := rest.Create(ctx, svc2)
|
||||
created_svc2 := <-c2
|
||||
created_service_2 := created_svc2.Object.(*api.Service)
|
||||
created_svc2, _ := rest.Create(ctx, svc2)
|
||||
created_service_2 := created_svc2.(*api.Service)
|
||||
if created_service_2.Name != "bar" {
|
||||
t.Errorf("Expected bar, but got %v", created_service_2.Name)
|
||||
}
|
||||
@ -453,9 +448,8 @@ func TestServiceRegistryIPAllocation(t *testing.T) {
|
||||
},
|
||||
}
|
||||
ctx = api.NewDefaultContext()
|
||||
c3, _ := rest.Create(ctx, svc3)
|
||||
created_svc3 := <-c3
|
||||
created_service_3 := created_svc3.Object.(*api.Service)
|
||||
created_svc3, _ := rest.Create(ctx, svc3)
|
||||
created_service_3 := created_svc3.(*api.Service)
|
||||
if created_service_3.Spec.PortalIP != "1.2.3.93" { // specific IP
|
||||
t.Errorf("Unexpected PortalIP: %s", created_service_3.Spec.PortalIP)
|
||||
}
|
||||
@ -478,9 +472,8 @@ func TestServiceRegistryIPReallocation(t *testing.T) {
|
||||
},
|
||||
}
|
||||
ctx := api.NewDefaultContext()
|
||||
c1, _ := rest.Create(ctx, svc1)
|
||||
created_svc1 := <-c1
|
||||
created_service_1 := created_svc1.Object.(*api.Service)
|
||||
created_svc1, _ := rest.Create(ctx, svc1)
|
||||
created_service_1 := created_svc1.(*api.Service)
|
||||
if created_service_1.Name != "foo" {
|
||||
t.Errorf("Expected foo, but got %v", created_service_1.Name)
|
||||
}
|
||||
@ -488,8 +481,7 @@ func TestServiceRegistryIPReallocation(t *testing.T) {
|
||||
t.Errorf("Unexpected PortalIP: %s", created_service_1.Spec.PortalIP)
|
||||
}
|
||||
|
||||
c, _ := rest.Delete(ctx, created_service_1.Name)
|
||||
<-c
|
||||
rest.Delete(ctx, created_service_1.Name)
|
||||
|
||||
svc2 := &api.Service{
|
||||
ObjectMeta: api.ObjectMeta{Name: "bar"},
|
||||
@ -501,9 +493,8 @@ func TestServiceRegistryIPReallocation(t *testing.T) {
|
||||
},
|
||||
}
|
||||
ctx = api.NewDefaultContext()
|
||||
c2, _ := rest.Create(ctx, svc2)
|
||||
created_svc2 := <-c2
|
||||
created_service_2 := created_svc2.Object.(*api.Service)
|
||||
created_svc2, _ := rest.Create(ctx, svc2)
|
||||
created_service_2 := created_svc2.(*api.Service)
|
||||
if created_service_2.Name != "bar" {
|
||||
t.Errorf("Expected bar, but got %v", created_service_2.Name)
|
||||
}
|
||||
@ -529,9 +520,8 @@ func TestServiceRegistryIPUpdate(t *testing.T) {
|
||||
},
|
||||
}
|
||||
ctx := api.NewDefaultContext()
|
||||
c, _ := rest.Create(ctx, svc)
|
||||
created_svc := <-c
|
||||
created_service := created_svc.Object.(*api.Service)
|
||||
created_svc, _ := rest.Create(ctx, svc)
|
||||
created_service := created_svc.(*api.Service)
|
||||
if created_service.Spec.Port != 6502 {
|
||||
t.Errorf("Expected port 6502, but got %v", created_service.Spec.Port)
|
||||
}
|
||||
@ -543,9 +533,8 @@ func TestServiceRegistryIPUpdate(t *testing.T) {
|
||||
*update = *created_service
|
||||
update.Spec.Port = 6503
|
||||
|
||||
c, _ = rest.Update(ctx, update)
|
||||
updated_svc := <-c
|
||||
updated_service := updated_svc.Object.(*api.Service)
|
||||
updated_svc, _, _ := rest.Update(ctx, update)
|
||||
updated_service := updated_svc.(*api.Service)
|
||||
if updated_service.Spec.Port != 6503 {
|
||||
t.Errorf("Expected port 6503, but got %v", updated_service.Spec.Port)
|
||||
}
|
||||
@ -554,7 +543,7 @@ func TestServiceRegistryIPUpdate(t *testing.T) {
|
||||
update.Spec.Port = 6503
|
||||
update.Spec.PortalIP = "1.2.3.76" // error
|
||||
|
||||
_, err := rest.Update(ctx, update)
|
||||
_, _, err := rest.Update(ctx, update)
|
||||
if err == nil || !errors.IsInvalid(err) {
|
||||
t.Error("Unexpected error type: %v", err)
|
||||
}
|
||||
@ -578,9 +567,8 @@ func TestServiceRegistryIPExternalLoadBalancer(t *testing.T) {
|
||||
},
|
||||
}
|
||||
ctx := api.NewDefaultContext()
|
||||
c, _ := rest.Create(ctx, svc)
|
||||
created_svc := <-c
|
||||
created_service := created_svc.Object.(*api.Service)
|
||||
created_svc, _ := rest.Create(ctx, svc)
|
||||
created_service := created_svc.(*api.Service)
|
||||
if created_service.Spec.Port != 6502 {
|
||||
t.Errorf("Expected port 6502, but got %v", created_service.Spec.Port)
|
||||
}
|
||||
@ -591,7 +579,7 @@ func TestServiceRegistryIPExternalLoadBalancer(t *testing.T) {
|
||||
update := new(api.Service)
|
||||
*update = *created_service
|
||||
|
||||
_, err := rest.Update(ctx, update)
|
||||
_, _, err := rest.Update(ctx, update)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error %v", err)
|
||||
}
|
||||
@ -614,8 +602,7 @@ func TestServiceRegistryIPReloadFromStorage(t *testing.T) {
|
||||
},
|
||||
}
|
||||
ctx := api.NewDefaultContext()
|
||||
c, _ := rest1.Create(ctx, svc)
|
||||
<-c
|
||||
rest1.Create(ctx, svc)
|
||||
svc = &api.Service{
|
||||
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: api.NamespaceDefault},
|
||||
Spec: api.ServiceSpec{
|
||||
@ -625,8 +612,7 @@ func TestServiceRegistryIPReloadFromStorage(t *testing.T) {
|
||||
SessionAffinity: api.AffinityTypeNone,
|
||||
},
|
||||
}
|
||||
c, _ = rest1.Create(ctx, svc)
|
||||
<-c
|
||||
rest1.Create(ctx, svc)
|
||||
|
||||
// This will reload from storage, finding the previous 2
|
||||
rest2 := NewREST(registry, fakeCloud, registrytest.NewMinionRegistry(machines, api.NodeResources{}), makeIPNet(t))
|
||||
@ -641,9 +627,8 @@ func TestServiceRegistryIPReloadFromStorage(t *testing.T) {
|
||||
SessionAffinity: api.AffinityTypeNone,
|
||||
},
|
||||
}
|
||||
c, _ = rest2.Create(ctx, svc)
|
||||
created_svc := <-c
|
||||
created_service := created_svc.Object.(*api.Service)
|
||||
created_svc, _ := rest2.Create(ctx, svc)
|
||||
created_service := created_svc.(*api.Service)
|
||||
if created_service.Spec.PortalIP != "1.2.3.3" {
|
||||
t.Errorf("Unexpected PortalIP: %s", created_service.Spec.PortalIP)
|
||||
}
|
||||
@ -657,9 +642,9 @@ func TestCreateServiceWithConflictingNamespace(t *testing.T) {
|
||||
}
|
||||
|
||||
ctx := api.NewDefaultContext()
|
||||
channel, err := storage.Create(ctx, service)
|
||||
if channel != nil {
|
||||
t.Error("Expected a nil channel, but we got a value")
|
||||
obj, err := storage.Create(ctx, service)
|
||||
if obj != nil {
|
||||
t.Error("Expected a nil object, but we got a value")
|
||||
}
|
||||
if err == nil {
|
||||
t.Errorf("Expected an error, but we didn't get one")
|
||||
@ -675,9 +660,9 @@ func TestUpdateServiceWithConflictingNamespace(t *testing.T) {
|
||||
}
|
||||
|
||||
ctx := api.NewDefaultContext()
|
||||
channel, err := storage.Update(ctx, service)
|
||||
if channel != nil {
|
||||
t.Error("Expected a nil channel, but we got a value")
|
||||
obj, created, err := storage.Update(ctx, service)
|
||||
if obj != nil || created {
|
||||
t.Error("Expected a nil object, but we got a value or created was true")
|
||||
}
|
||||
if err == nil {
|
||||
t.Errorf("Expected an error, but we didn't get one")
|
||||
|
@ -175,6 +175,7 @@ var timeoutFlag = "?timeout=60s"
|
||||
// Requests to try. Each one should be forbidden or not forbidden
|
||||
// depending on the authentication and authorization setup of the master.
|
||||
var code200 = map[int]bool{200: true}
|
||||
var code201 = map[int]bool{201: true}
|
||||
var code400 = map[int]bool{400: true}
|
||||
var code403 = map[int]bool{403: true}
|
||||
var code404 = map[int]bool{404: true}
|
||||
@ -197,7 +198,7 @@ func getTestRequests() []struct {
|
||||
}{
|
||||
// Normal methods on pods
|
||||
{"GET", "/api/v1beta1/pods", "", code200},
|
||||
{"POST", "/api/v1beta1/pods" + timeoutFlag, aPod, code200},
|
||||
{"POST", "/api/v1beta1/pods" + timeoutFlag, aPod, code201},
|
||||
{"PUT", "/api/v1beta1/pods/a" + timeoutFlag, aPod, code200},
|
||||
{"GET", "/api/v1beta1/pods", "", code200},
|
||||
{"GET", "/api/v1beta1/pods/a", "", code200},
|
||||
@ -217,7 +218,7 @@ func getTestRequests() []struct {
|
||||
|
||||
// Normal methods on services
|
||||
{"GET", "/api/v1beta1/services", "", code200},
|
||||
{"POST", "/api/v1beta1/services" + timeoutFlag, aService, code200},
|
||||
{"POST", "/api/v1beta1/services" + timeoutFlag, aService, code201},
|
||||
{"PUT", "/api/v1beta1/services/a" + timeoutFlag, aService, code200},
|
||||
{"GET", "/api/v1beta1/services", "", code200},
|
||||
{"GET", "/api/v1beta1/services/a", "", code200},
|
||||
@ -225,7 +226,7 @@ func getTestRequests() []struct {
|
||||
|
||||
// Normal methods on replicationControllers
|
||||
{"GET", "/api/v1beta1/replicationControllers", "", code200},
|
||||
{"POST", "/api/v1beta1/replicationControllers" + timeoutFlag, aRC, code200},
|
||||
{"POST", "/api/v1beta1/replicationControllers" + timeoutFlag, aRC, code201},
|
||||
{"PUT", "/api/v1beta1/replicationControllers/a" + timeoutFlag, aRC, code200},
|
||||
{"GET", "/api/v1beta1/replicationControllers", "", code200},
|
||||
{"GET", "/api/v1beta1/replicationControllers/a", "", code200},
|
||||
@ -233,7 +234,7 @@ func getTestRequests() []struct {
|
||||
|
||||
// Normal methods on endpoints
|
||||
{"GET", "/api/v1beta1/endpoints", "", code200},
|
||||
{"POST", "/api/v1beta1/endpoints" + timeoutFlag, aEndpoints, code200},
|
||||
{"POST", "/api/v1beta1/endpoints" + timeoutFlag, aEndpoints, code201},
|
||||
{"PUT", "/api/v1beta1/endpoints/a" + timeoutFlag, aEndpoints, code200},
|
||||
{"GET", "/api/v1beta1/endpoints", "", code200},
|
||||
{"GET", "/api/v1beta1/endpoints/a", "", code200},
|
||||
@ -241,7 +242,7 @@ func getTestRequests() []struct {
|
||||
|
||||
// Normal methods on minions
|
||||
{"GET", "/api/v1beta1/minions", "", code200},
|
||||
{"POST", "/api/v1beta1/minions" + timeoutFlag, aMinion, code200},
|
||||
{"POST", "/api/v1beta1/minions" + timeoutFlag, aMinion, code201},
|
||||
{"PUT", "/api/v1beta1/minions/a" + timeoutFlag, aMinion, code409}, // See #2115 about why 409
|
||||
{"GET", "/api/v1beta1/minions", "", code200},
|
||||
{"GET", "/api/v1beta1/minions/a", "", code200},
|
||||
@ -249,7 +250,7 @@ func getTestRequests() []struct {
|
||||
|
||||
// Normal methods on events
|
||||
{"GET", "/api/v1beta1/events", "", code200},
|
||||
{"POST", "/api/v1beta1/events" + timeoutFlag, aEvent, code200},
|
||||
{"POST", "/api/v1beta1/events" + timeoutFlag, aEvent, code201},
|
||||
{"PUT", "/api/v1beta1/events/a" + timeoutFlag, aEvent, code200},
|
||||
{"GET", "/api/v1beta1/events", "", code200},
|
||||
{"GET", "/api/v1beta1/events", "", code200},
|
||||
@ -258,8 +259,8 @@ func getTestRequests() []struct {
|
||||
|
||||
// Normal methods on bindings
|
||||
{"GET", "/api/v1beta1/bindings", "", code405}, // Bindings are write-only
|
||||
{"POST", "/api/v1beta1/pods" + timeoutFlag, aPod, code200}, // Need a pod to bind or you get a 404
|
||||
{"POST", "/api/v1beta1/bindings" + timeoutFlag, aBinding, code200},
|
||||
{"POST", "/api/v1beta1/pods" + timeoutFlag, aPod, code201}, // Need a pod to bind or you get a 404
|
||||
{"POST", "/api/v1beta1/bindings" + timeoutFlag, aBinding, code201},
|
||||
{"PUT", "/api/v1beta1/bindings/a" + timeoutFlag, aBinding, code404},
|
||||
{"GET", "/api/v1beta1/bindings", "", code405},
|
||||
{"GET", "/api/v1beta1/bindings/a", "", code404}, // No bindings instances
|
||||
@ -727,7 +728,7 @@ func TestNamespaceAuthorization(t *testing.T) {
|
||||
statusCodes map[int]bool // allowed status codes.
|
||||
}{
|
||||
|
||||
{"POST", "/api/v1beta1/pods" + timeoutFlag + "&namespace=foo", "foo", aPod, code200},
|
||||
{"POST", "/api/v1beta1/pods" + timeoutFlag + "&namespace=foo", "foo", aPod, code201},
|
||||
{"GET", "/api/v1beta1/pods?namespace=foo", "foo", "", code200},
|
||||
{"GET", "/api/v1beta1/pods/a?namespace=foo", "foo", "", code200},
|
||||
{"DELETE", "/api/v1beta1/pods/a" + timeoutFlag + "&namespace=foo", "foo", "", code200},
|
||||
@ -838,7 +839,7 @@ func TestKindAuthorization(t *testing.T) {
|
||||
body string
|
||||
statusCodes map[int]bool // allowed status codes.
|
||||
}{
|
||||
{"POST", "/api/v1beta1/services" + timeoutFlag, aService, code200},
|
||||
{"POST", "/api/v1beta1/services" + timeoutFlag, aService, code201},
|
||||
{"GET", "/api/v1beta1/services", "", code200},
|
||||
{"GET", "/api/v1beta1/services/a", "", code200},
|
||||
{"DELETE", "/api/v1beta1/services/a" + timeoutFlag, "", code200},
|
||||
|
Loading…
Reference in New Issue
Block a user