From 26f08b78076f679022bd2eedfca67316dc0269bf Mon Sep 17 00:00:00 2001 From: Clayton Coleman Date: Tue, 10 Feb 2015 12:49:56 -0500 Subject: [PATCH] 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. --- pkg/registry/binding/rest.go | 14 ++- pkg/registry/binding/rest_test.go | 22 ++-- pkg/registry/controller/rest.go | 41 ++++--- pkg/registry/controller/rest_test.go | 25 ++--- pkg/registry/endpoint/rest.go | 32 +++--- pkg/registry/event/rest.go | 42 ++++---- pkg/registry/event/rest_test.go | 18 ++-- pkg/registry/limitrange/rest.go | 43 ++++---- pkg/registry/minion/rest.go | 41 +++---- pkg/registry/minion/rest_test.go | 16 ++- pkg/registry/namespace/rest.go | 42 +++----- pkg/registry/namespace/rest_test.go | 18 ++-- pkg/registry/pod/rest.go | 48 ++++----- pkg/registry/pod/rest_test.go | 53 ++++----- pkg/registry/resourcequota/rest.go | 43 ++++---- pkg/registry/resourcequotausage/rest.go | 13 +-- pkg/registry/service/rest.go | 136 +++++++++++------------- pkg/registry/service/rest_test.go | 107 ++++++++----------- test/integration/auth_test.go | 21 ++-- 19 files changed, 333 insertions(+), 442 deletions(-) diff --git a/pkg/registry/binding/rest.go b/pkg/registry/binding/rest.go index 52907852c93..42d7970870e 100644 --- a/pkg/registry/binding/rest.go +++ b/pkg/registry/binding/rest.go @@ -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 } diff --git a/pkg/registry/binding/rest_test.go b/pkg/registry/binding/rest_test.go index 134d3df5481..5ddac234105 100644 --- a/pkg/registry/binding/rest_test.go +++ b/pkg/registry/binding/rest_test.go @@ -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) } } diff --git a/pkg/registry/controller/rest.go b/pkg/registry/controller/rest.go index 94c13664ef1..4ea56e49618 100644 --- a/pkg/registry/controller/rest.go +++ b/pkg/registry/controller/rest.go @@ -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. diff --git a/pkg/registry/controller/rest_test.go b/pkg/registry/controller/rest_test.go index 577b1061415..9616c654210 100644 --- a/pkg/registry/controller/rest_test.go +++ b/pkg/registry/controller/rest_test.go @@ -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") diff --git a/pkg/registry/endpoint/rest.go b/pkg/registry/endpoint/rest.go index 40a7831fc23..147a9df248c 100644 --- a/pkg/registry/endpoint/rest.go +++ b/pkg/registry/endpoint/rest.go @@ -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. diff --git a/pkg/registry/event/rest.go b/pkg/registry/event/rest.go index 216c356d032..c9307eb86d8 100644 --- a/pkg/registry/event/rest.go +++ b/pkg/registry/event/rest.go @@ -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) { diff --git a/pkg/registry/event/rest_test.go b/pkg/registry/event/rest_test.go index 922603dd9b0..cbcce2fbe11 100644 --- a/pkg/registry/event/rest_test.go +++ b/pkg/registry/event/rest_test.go @@ -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) diff --git a/pkg/registry/limitrange/rest.go b/pkg/registry/limitrange/rest.go index f5eaaa1a71d..878dfc46ebd 100644 --- a/pkg/registry/limitrange/rest.go +++ b/pkg/registry/limitrange/rest.go @@ -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 diff --git a/pkg/registry/minion/rest.go b/pkg/registry/minion/rest.go index 5c0ab637383..cd6db1ef475 100644 --- a/pkg/registry/minion/rest.go +++ b/pkg/registry/minion/rest.go @@ -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. diff --git a/pkg/registry/minion/rest_test.go b/pkg/registry/minion/rest_test.go index 0e3e2c87b83..fe53157e31a 100644 --- a/pkg/registry/minion/rest_test.go +++ b/pkg/registry/minion/rest_test.go @@ -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) diff --git a/pkg/registry/namespace/rest.go b/pkg/registry/namespace/rest.go index eeaad26519d..21a6a45bf61 100644 --- a/pkg/registry/namespace/rest.go +++ b/pkg/registry/namespace/rest.go @@ -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) { diff --git a/pkg/registry/namespace/rest_test.go b/pkg/registry/namespace/rest_test.go index e053e4dd215..9a694984489 100644 --- a/pkg/registry/namespace/rest_test.go +++ b/pkg/registry/namespace/rest_test.go @@ -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) diff --git a/pkg/registry/pod/rest.go b/pkg/registry/pod/rest.go index b27290b1fdb..4e7c995ae69 100644 --- a/pkg/registry/pod/rest.go +++ b/pkg/registry/pod/rest.go @@ -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. diff --git a/pkg/registry/pod/rest_test.go b/pkg/registry/pod/rest_test.go index e0b2c1c9031..ff133675499 100644 --- a/pkg/registry/pod/rest_test.go +++ b/pkg/registry/pod/rest_test.go @@ -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) } } diff --git a/pkg/registry/resourcequota/rest.go b/pkg/registry/resourcequota/rest.go index 3f22be18826..e577e0cc516 100644 --- a/pkg/registry/resourcequota/rest.go +++ b/pkg/registry/resourcequota/rest.go @@ -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 diff --git a/pkg/registry/resourcequotausage/rest.go b/pkg/registry/resourcequotausage/rest.go index cfd63cf4c7a..b2d9a51454e 100644 --- a/pkg/registry/resourcequotausage/rest.go +++ b/pkg/registry/resourcequotausage/rest.go @@ -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 } diff --git a/pkg/registry/service/rest.go b/pkg/registry/service/rest.go index 638cf592c84..a2906179219 100644 --- a/pkg/registry/service/rest.go +++ b/pkg/registry/service/rest.go @@ -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. diff --git a/pkg/registry/service/rest_test.go b/pkg/registry/service/rest_test.go index 8d228844734..60a3096015f 100644 --- a/pkg/registry/service/rest_test.go +++ b/pkg/registry/service/rest_test.go @@ -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") diff --git a/test/integration/auth_test.go b/test/integration/auth_test.go index 63b66e51a08..4f761589bd9 100644 --- a/test/integration/auth_test.go +++ b/test/integration/auth_test.go @@ -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},