diff --git a/pkg/api/rest/create_test.go b/pkg/api/rest/create_test.go deleted file mode 100644 index 8bf7ef696ea..00000000000 --- a/pkg/api/rest/create_test.go +++ /dev/null @@ -1,41 +0,0 @@ -/* -Copyright 2014 The Kubernetes Authors All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package rest - -import ( - "testing" - - "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/api/errors" -) - -func TestCheckGeneratedNameError(t *testing.T) { - expect := errors.NewNotFound("foo", "bar") - if err := CheckGeneratedNameError(Services, expect, &api.Pod{}); err != expect { - t.Errorf("NotFoundError should be ignored: %v", err) - } - - expect = errors.NewAlreadyExists("foo", "bar") - if err := CheckGeneratedNameError(Services, expect, &api.Pod{}); err != expect { - t.Errorf("AlreadyExists should be returned when no GenerateName field: %v", err) - } - - expect = errors.NewAlreadyExists("foo", "bar") - if err := CheckGeneratedNameError(Services, expect, &api.Pod{ObjectMeta: api.ObjectMeta{GenerateName: "foo"}}); err == nil || !errors.IsServerTimeout(err) { - t.Errorf("expected try again later error: %v", err) - } -} diff --git a/pkg/api/rest/types.go b/pkg/api/rest/types.go index 8701f9c043b..0e7f048ba51 100644 --- a/pkg/api/rest/types.go +++ b/pkg/api/rest/types.go @@ -17,10 +17,7 @@ limitations under the License. package rest import ( - "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/api/validation" "k8s.io/kubernetes/pkg/runtime" - "k8s.io/kubernetes/pkg/util/fielderrors" ) // ObjectFunc is a function to act on a given object. An error may be returned @@ -43,51 +40,3 @@ func AllFuncs(fns ...ObjectFunc) ObjectFunc { return nil } } - -// svcStrategy implements behavior for Services -// TODO: move to a service specific package. -type svcStrategy struct { - runtime.ObjectTyper - api.NameGenerator -} - -// Services is the default logic that applies when creating and updating Service -// objects. -var Services = svcStrategy{api.Scheme, api.SimpleNameGenerator} - -// NamespaceScoped is true for services. -func (svcStrategy) NamespaceScoped() bool { - return true -} - -// PrepareForCreate clears fields that are not allowed to be set by end users on creation. -func (svcStrategy) PrepareForCreate(obj runtime.Object) { - service := obj.(*api.Service) - service.Status = api.ServiceStatus{} -} - -// PrepareForUpdate clears fields that are not allowed to be set by end users on update. -func (svcStrategy) PrepareForUpdate(obj, old runtime.Object) { - // TODO: once service has a status sub-resource we can enable this. - //newService := obj.(*api.Service) - //oldService := old.(*api.Service) - //newService.Status = oldService.Status -} - -// Validate validates a new service. -func (svcStrategy) Validate(ctx api.Context, obj runtime.Object) fielderrors.ValidationErrorList { - service := obj.(*api.Service) - return validation.ValidateService(service) -} - -func (svcStrategy) AllowCreateOnUpdate() bool { - return true -} - -func (svcStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) fielderrors.ValidationErrorList { - return validation.ValidateServiceUpdate(old.(*api.Service), obj.(*api.Service)) -} - -func (svcStrategy) AllowUnconditionalUpdate() bool { - return true -} diff --git a/pkg/master/controller.go b/pkg/master/controller.go index 328ba01a03a..fc5f728d5f4 100644 --- a/pkg/master/controller.go +++ b/pkg/master/controller.go @@ -211,7 +211,7 @@ func (c *Controller) CreateOrUpdateMasterServiceIfNeeded(serviceName string, ser Type: serviceType, }, } - if err := rest.BeforeCreate(rest.Services, ctx, svc); err != nil { + if err := rest.BeforeCreate(service.Strategy, ctx, svc); err != nil { return err } diff --git a/pkg/registry/node/strategy.go b/pkg/registry/node/strategy.go index 7a903984cc3..c8167812991 100644 --- a/pkg/registry/node/strategy.go +++ b/pkg/registry/node/strategy.go @@ -112,7 +112,7 @@ type ResourceGetter interface { Get(api.Context, string) (runtime.Object, error) } -// NodeToSelectableFields returns a label set that represents the object. +// NodeToSelectableFields returns a field set that represents the object. func NodeToSelectableFields(node *api.Node) fields.Set { objectMetaFieldsSet := generic.ObjectMetaFieldsSet(node.ObjectMeta, false) specificFieldsSet := fields.Set{ diff --git a/pkg/registry/service/etcd/etcd.go b/pkg/registry/service/etcd/etcd.go index ca9b04021ed..7f1a6f4340b 100644 --- a/pkg/registry/service/etcd/etcd.go +++ b/pkg/registry/service/etcd/etcd.go @@ -17,14 +17,12 @@ limitations under the License. package etcd import ( - "fmt" - "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/api/rest" "k8s.io/kubernetes/pkg/fields" "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/generic" etcdgeneric "k8s.io/kubernetes/pkg/registry/generic/etcd" + "k8s.io/kubernetes/pkg/registry/service" "k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/storage" ) @@ -49,29 +47,14 @@ func NewREST(s storage.Interface) *REST { return obj.(*api.Service).Name, nil }, PredicateFunc: func(label labels.Selector, field fields.Selector) generic.Matcher { - return MatchServices(label, field) + return service.MatchServices(label, field) }, EndpointName: "services", - CreateStrategy: rest.Services, - UpdateStrategy: rest.Services, + CreateStrategy: service.Strategy, + UpdateStrategy: service.Strategy, Storage: s, } return &REST{store} } - -// FIXME: Move it. -func MatchServices(label labels.Selector, field fields.Selector) generic.Matcher { - return &generic.SelectionPredicate{Label: label, Field: field, GetAttrs: ServiceAttributes} -} - -func ServiceAttributes(obj runtime.Object) (objLabels labels.Set, objFields fields.Set, err error) { - service, ok := obj.(*api.Service) - if !ok { - return nil, nil, fmt.Errorf("invalid object type %#v", obj) - } - return service.Labels, fields.Set{ - "metadata.name": service.Name, - }, nil -} diff --git a/pkg/registry/service/rest.go b/pkg/registry/service/rest.go index 46b55dd6266..2ae91c3a3d2 100644 --- a/pkg/registry/service/rest.go +++ b/pkg/registry/service/rest.go @@ -63,7 +63,7 @@ func NewStorage(registry Registry, endpoints endpoint.Registry, serviceIPs ipall 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 { + if err := rest.BeforeCreate(Strategy, ctx, obj); err != nil { return nil, err } @@ -118,7 +118,7 @@ func (rs *REST) Create(ctx api.Context, obj runtime.Object) (runtime.Object, err out, err := rs.registry.CreateService(ctx, service) if err != nil { - err = rest.CheckGeneratedNameError(rest.Services, err, service) + err = rest.CheckGeneratedNameError(Strategy, err, service) } if err == nil { diff --git a/pkg/registry/service/strategy.go b/pkg/registry/service/strategy.go new file mode 100644 index 00000000000..80b6ca302c5 --- /dev/null +++ b/pkg/registry/service/strategy.go @@ -0,0 +1,94 @@ +/* +Copyright 2014 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package service + +import ( + "fmt" + + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/validation" + "k8s.io/kubernetes/pkg/fields" + "k8s.io/kubernetes/pkg/labels" + "k8s.io/kubernetes/pkg/registry/generic" + "k8s.io/kubernetes/pkg/runtime" + "k8s.io/kubernetes/pkg/util/fielderrors" +) + +// svcStrategy implements behavior for Services +type svcStrategy struct { + runtime.ObjectTyper + api.NameGenerator +} + +// Services is the default logic that applies when creating and updating Service +// objects. +var Strategy = svcStrategy{api.Scheme, api.SimpleNameGenerator} + +// NamespaceScoped is true for services. +func (svcStrategy) NamespaceScoped() bool { + return true +} + +// PrepareForCreate clears fields that are not allowed to be set by end users on creation. +func (svcStrategy) PrepareForCreate(obj runtime.Object) { + service := obj.(*api.Service) + service.Status = api.ServiceStatus{} +} + +// PrepareForUpdate clears fields that are not allowed to be set by end users on update. +func (svcStrategy) PrepareForUpdate(obj, old runtime.Object) { + // TODO: once service has a status sub-resource we can enable this. + //newService := obj.(*api.Service) + //oldService := old.(*api.Service) + //newService.Status = oldService.Status +} + +// Validate validates a new service. +func (svcStrategy) Validate(ctx api.Context, obj runtime.Object) fielderrors.ValidationErrorList { + service := obj.(*api.Service) + return validation.ValidateService(service) +} + +func (svcStrategy) AllowCreateOnUpdate() bool { + return true +} + +func (svcStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) fielderrors.ValidationErrorList { + return validation.ValidateServiceUpdate(old.(*api.Service), obj.(*api.Service)) +} + +func (svcStrategy) AllowUnconditionalUpdate() bool { + return true +} + +func MatchServices(label labels.Selector, field fields.Selector) generic.Matcher { + return &generic.SelectionPredicate{ + Label: label, + Field: field, + GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) { + service, ok := obj.(*api.Service) + if !ok { + return nil, nil, fmt.Errorf("Given object is not a service") + } + return labels.Set(service.ObjectMeta.Labels), ServiceToSelectableFields(service), nil + }, + } +} + +func ServiceToSelectableFields(service *api.Service) fields.Set { + return generic.ObjectMetaFieldsSet(service.ObjectMeta, true) +} diff --git a/pkg/api/rest/update_test.go b/pkg/registry/service/strategy_test.go similarity index 75% rename from pkg/api/rest/update_test.go rename to pkg/registry/service/strategy_test.go index d5512cbad4c..9af7a51acc4 100644 --- a/pkg/api/rest/update_test.go +++ b/pkg/registry/service/strategy_test.go @@ -14,16 +14,35 @@ See the License for the specific language governing permissions and limitations under the License. */ -package rest +package service import ( "testing" "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/errors" + "k8s.io/kubernetes/pkg/api/rest" "k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/util" ) +func TestCheckGeneratedNameError(t *testing.T) { + expect := errors.NewNotFound("foo", "bar") + if err := rest.CheckGeneratedNameError(Strategy, expect, &api.Pod{}); err != expect { + t.Errorf("NotFoundError should be ignored: %v", err) + } + + expect = errors.NewAlreadyExists("foo", "bar") + if err := rest.CheckGeneratedNameError(Strategy, expect, &api.Pod{}); err != expect { + t.Errorf("AlreadyExists should be returned when no GenerateName field: %v", err) + } + + expect = errors.NewAlreadyExists("foo", "bar") + if err := rest.CheckGeneratedNameError(Strategy, expect, &api.Pod{ObjectMeta: api.ObjectMeta{GenerateName: "foo"}}); err == nil || !errors.IsServerTimeout(err) { + t.Errorf("expected try again later error: %v", err) + } +} + func makeValidService() api.Service { return api.Service{ ObjectMeta: api.ObjectMeta{ @@ -99,7 +118,7 @@ func TestBeforeUpdate(t *testing.T) { newSvc := makeValidService() tc.tweakSvc(&oldSvc, &newSvc) ctx := api.NewDefaultContext() - err := BeforeUpdate(Services, ctx, runtime.Object(&oldSvc), runtime.Object(&newSvc)) + err := rest.BeforeUpdate(Strategy, ctx, runtime.Object(&oldSvc), runtime.Object(&newSvc)) if tc.expectErr && err == nil { t.Errorf("unexpected non-error for %q", tc.name) }