Unverified Commit 40212c17 authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #54484 from sttts/sttts-split-psp

Automatic merge from submit-queue. If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. admission: wire through validating-only admission Based on https://github.com/kubernetes/kubernetes/pull/54232. This is important and required for beta because it affects the shape of the webhook admission plugins that are going to be produced and is needed to make sure that our existing chain continues to properly verify and protect the API objects based on their final state after webhook admission mutators run. We discussed this in the October 11 API machinery call with @erictune and @caesarxuchao and we agreed to do this as a requirement for beta. See this part of the recording: https://www.youtube.com/watch?v=mrgDPHyr4VY#t=325 .
parents 7aed6630 35bb6823
...@@ -34,13 +34,13 @@ import ( ...@@ -34,13 +34,13 @@ import (
// WantsInternalKubeClientSet defines a function which sets ClientSet for admission plugins that need it // WantsInternalKubeClientSet defines a function which sets ClientSet for admission plugins that need it
type WantsInternalKubeClientSet interface { type WantsInternalKubeClientSet interface {
SetInternalKubeClientSet(internalclientset.Interface) SetInternalKubeClientSet(internalclientset.Interface)
admission.Validator admission.InitializationValidator
} }
// WantsInternalKubeInformerFactory defines a function which sets InformerFactory for admission plugins that need it // WantsInternalKubeInformerFactory defines a function which sets InformerFactory for admission plugins that need it
type WantsInternalKubeInformerFactory interface { type WantsInternalKubeInformerFactory interface {
SetInternalKubeInformerFactory(informers.SharedInformerFactory) SetInternalKubeInformerFactory(informers.SharedInformerFactory)
admission.Validator admission.InitializationValidator
} }
// WantsCloudConfig defines a function which sets CloudConfig for admission plugins that need it. // WantsCloudConfig defines a function which sets CloudConfig for admission plugins that need it.
...@@ -56,7 +56,7 @@ type WantsRESTMapper interface { ...@@ -56,7 +56,7 @@ type WantsRESTMapper interface {
// WantsQuotaConfiguration defines a function which sets quota configuration for admission plugins that need it. // WantsQuotaConfiguration defines a function which sets quota configuration for admission plugins that need it.
type WantsQuotaConfiguration interface { type WantsQuotaConfiguration interface {
SetQuotaConfiguration(quota.Configuration) SetQuotaConfiguration(quota.Configuration)
admission.Validator admission.InitializationValidator
} }
// WantsServiceResolver defines a fuction that accepts a ServiceResolver for // WantsServiceResolver defines a fuction that accepts a ServiceResolver for
...@@ -75,7 +75,7 @@ type ServiceResolver interface { ...@@ -75,7 +75,7 @@ type ServiceResolver interface {
// to allow the apiserver to control what is returned as auth info // to allow the apiserver to control what is returned as auth info
type WantsAuthenticationInfoResolverWrapper interface { type WantsAuthenticationInfoResolverWrapper interface {
SetAuthenticationInfoResolverWrapper(webhook.AuthenticationInfoResolverWrapper) SetAuthenticationInfoResolverWrapper(webhook.AuthenticationInfoResolverWrapper)
admission.Validator admission.InitializationValidator
} }
type PluginInitializer struct { type PluginInitializer struct {
......
...@@ -21,6 +21,7 @@ go_library( ...@@ -21,6 +21,7 @@ go_library(
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library", "//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library",
"//vendor/k8s.io/apiserver/pkg/registry/rest:go_default_library",
"//vendor/k8s.io/apiserver/pkg/storage:go_default_library", "//vendor/k8s.io/apiserver/pkg/storage:go_default_library",
"//vendor/k8s.io/client-go/util/retry:go_default_library", "//vendor/k8s.io/client-go/util/retry:go_default_library",
], ],
......
...@@ -33,6 +33,7 @@ import ( ...@@ -33,6 +33,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
kruntime "k8s.io/apimachinery/pkg/runtime" kruntime "k8s.io/apimachinery/pkg/runtime"
apirequest "k8s.io/apiserver/pkg/endpoints/request" apirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/registry/rest"
"k8s.io/apiserver/pkg/storage" "k8s.io/apiserver/pkg/storage"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/endpoints" "k8s.io/kubernetes/pkg/api/endpoints"
...@@ -220,7 +221,7 @@ func (r *leaseEndpointReconciler) doReconcile(serviceName string, endpointPorts ...@@ -220,7 +221,7 @@ func (r *leaseEndpointReconciler) doReconcile(serviceName string, endpointPorts
} }
glog.Warningf("Resetting endpoints for master service %q to %v", serviceName, masterIPs) glog.Warningf("Resetting endpoints for master service %q to %v", serviceName, masterIPs)
return r.endpointRegistry.UpdateEndpoints(ctx, e) return r.endpointRegistry.UpdateEndpoints(ctx, e, rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
} }
// checkEndpointSubsetFormatWithLease determines if the endpoint is in the // checkEndpointSubsetFormatWithLease determines if the endpoint is in the
......
...@@ -33,8 +33,8 @@ type Registry interface { ...@@ -33,8 +33,8 @@ type Registry interface {
ListStatefulSets(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*apps.StatefulSetList, error) ListStatefulSets(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*apps.StatefulSetList, error)
WatchStatefulSets(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error) WatchStatefulSets(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error)
GetStatefulSet(ctx genericapirequest.Context, statefulSetID string, options *metav1.GetOptions) (*apps.StatefulSet, error) GetStatefulSet(ctx genericapirequest.Context, statefulSetID string, options *metav1.GetOptions) (*apps.StatefulSet, error)
CreateStatefulSet(ctx genericapirequest.Context, statefulSet *apps.StatefulSet) (*apps.StatefulSet, error) CreateStatefulSet(ctx genericapirequest.Context, statefulSet *apps.StatefulSet, createValidation rest.ValidateObjectFunc) (*apps.StatefulSet, error)
UpdateStatefulSet(ctx genericapirequest.Context, statefulSet *apps.StatefulSet) (*apps.StatefulSet, error) UpdateStatefulSet(ctx genericapirequest.Context, statefulSet *apps.StatefulSet, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (*apps.StatefulSet, error)
DeleteStatefulSet(ctx genericapirequest.Context, statefulSetID string) error DeleteStatefulSet(ctx genericapirequest.Context, statefulSetID string) error
} }
...@@ -72,16 +72,16 @@ func (s *storage) GetStatefulSet(ctx genericapirequest.Context, statefulSetID st ...@@ -72,16 +72,16 @@ func (s *storage) GetStatefulSet(ctx genericapirequest.Context, statefulSetID st
return obj.(*apps.StatefulSet), nil return obj.(*apps.StatefulSet), nil
} }
func (s *storage) CreateStatefulSet(ctx genericapirequest.Context, statefulSet *apps.StatefulSet) (*apps.StatefulSet, error) { func (s *storage) CreateStatefulSet(ctx genericapirequest.Context, statefulSet *apps.StatefulSet, createValidation rest.ValidateObjectFunc) (*apps.StatefulSet, error) {
obj, err := s.Create(ctx, statefulSet, false) obj, err := s.Create(ctx, statefulSet, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return obj.(*apps.StatefulSet), nil return obj.(*apps.StatefulSet), nil
} }
func (s *storage) UpdateStatefulSet(ctx genericapirequest.Context, statefulSet *apps.StatefulSet) (*apps.StatefulSet, error) { func (s *storage) UpdateStatefulSet(ctx genericapirequest.Context, statefulSet *apps.StatefulSet, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (*apps.StatefulSet, error) {
obj, _, err := s.Update(ctx, statefulSet.Name, rest.DefaultUpdatedObjectInfo(statefulSet)) obj, _, err := s.Update(ctx, statefulSet.Name, rest.DefaultUpdatedObjectInfo(statefulSet), createValidation, updateValidation)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -108,8 +108,8 @@ func (r *StatusREST) Get(ctx genericapirequest.Context, name string, options *me ...@@ -108,8 +108,8 @@ func (r *StatusREST) Get(ctx genericapirequest.Context, name string, options *me
} }
// Update alters the status subset of an object. // Update alters the status subset of an object.
func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo) return r.store.Update(ctx, name, objInfo, createValidation, updateValidation)
} }
// Implement ShortNamesProvider // Implement ShortNamesProvider
...@@ -156,7 +156,7 @@ func (r *ScaleREST) Get(ctx genericapirequest.Context, name string, options *met ...@@ -156,7 +156,7 @@ func (r *ScaleREST) Get(ctx genericapirequest.Context, name string, options *met
return scale, err return scale, err
} }
func (r *ScaleREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { func (r *ScaleREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
ss, err := r.registry.GetStatefulSet(ctx, name, &metav1.GetOptions{}) ss, err := r.registry.GetStatefulSet(ctx, name, &metav1.GetOptions{})
if err != nil { if err != nil {
return nil, false, err return nil, false, err
...@@ -185,7 +185,7 @@ func (r *ScaleREST) Update(ctx genericapirequest.Context, name string, objInfo r ...@@ -185,7 +185,7 @@ func (r *ScaleREST) Update(ctx genericapirequest.Context, name string, objInfo r
ss.Spec.Replicas = scale.Spec.Replicas ss.Spec.Replicas = scale.Spec.Replicas
ss.ResourceVersion = scale.ResourceVersion ss.ResourceVersion = scale.ResourceVersion
ss, err = r.registry.UpdateStatefulSet(ctx, ss) ss, err = r.registry.UpdateStatefulSet(ctx, ss, createValidation, updateValidation)
if err != nil { if err != nil {
return nil, false, err return nil, false, err
} }
......
...@@ -46,7 +46,7 @@ func newStorage(t *testing.T) (StatefulSetStorage, *etcdtesting.EtcdTestServer) ...@@ -46,7 +46,7 @@ func newStorage(t *testing.T) (StatefulSetStorage, *etcdtesting.EtcdTestServer)
// createStatefulSet is a helper function that returns a StatefulSet with the updated resource version. // createStatefulSet is a helper function that returns a StatefulSet with the updated resource version.
func createStatefulSet(storage *REST, ps apps.StatefulSet, t *testing.T) (apps.StatefulSet, error) { func createStatefulSet(storage *REST, ps apps.StatefulSet, t *testing.T) (apps.StatefulSet, error) {
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), ps.Namespace) ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), ps.Namespace)
obj, err := storage.Create(ctx, &ps, false) obj, err := storage.Create(ctx, &ps, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Errorf("Failed to create StatefulSet, %v", err) t.Errorf("Failed to create StatefulSet, %v", err)
} }
...@@ -125,7 +125,7 @@ func TestStatusUpdate(t *testing.T) { ...@@ -125,7 +125,7 @@ func TestStatusUpdate(t *testing.T) {
}, },
} }
if _, _, err := storage.Status.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update)); err != nil { if _, _, err := storage.Status.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc); err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
obj, err := storage.StatefulSet.Get(ctx, "foo", &metav1.GetOptions{}) obj, err := storage.StatefulSet.Get(ctx, "foo", &metav1.GetOptions{})
...@@ -274,7 +274,7 @@ func TestScaleUpdate(t *testing.T) { ...@@ -274,7 +274,7 @@ func TestScaleUpdate(t *testing.T) {
}, },
} }
if _, _, err := storage.Scale.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update)); err != nil { if _, _, err := storage.Scale.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc); err != nil {
t.Fatalf("error updating scale %v: %v", update, err) t.Fatalf("error updating scale %v: %v", update, err)
} }
...@@ -290,7 +290,7 @@ func TestScaleUpdate(t *testing.T) { ...@@ -290,7 +290,7 @@ func TestScaleUpdate(t *testing.T) {
update.ResourceVersion = sts.ResourceVersion update.ResourceVersion = sts.ResourceVersion
update.Spec.Replicas = 15 update.Spec.Replicas = 15
if _, _, err = storage.Scale.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update)); err != nil && !errors.IsConflict(err) { if _, _, err = storage.Scale.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc); err != nil && !errors.IsConflict(err) {
t.Fatalf("unexpected error, expecting an update conflict but got %v", err) t.Fatalf("unexpected error, expecting an update conflict but got %v", err)
} }
} }
......
...@@ -15,6 +15,7 @@ go_library( ...@@ -15,6 +15,7 @@ go_library(
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library", "//vendor/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library",
"//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library", "//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library",
"//vendor/k8s.io/apiserver/pkg/registry/rest:go_default_library",
], ],
) )
......
...@@ -24,6 +24,7 @@ import ( ...@@ -24,6 +24,7 @@ import (
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/authentication/authenticator" "k8s.io/apiserver/pkg/authentication/authenticator"
genericapirequest "k8s.io/apiserver/pkg/endpoints/request" genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/registry/rest"
"k8s.io/kubernetes/pkg/apis/authentication" "k8s.io/kubernetes/pkg/apis/authentication"
) )
...@@ -39,7 +40,7 @@ func (r *REST) New() runtime.Object { ...@@ -39,7 +40,7 @@ func (r *REST) New() runtime.Object {
return &authentication.TokenReview{} return &authentication.TokenReview{}
} }
func (r *REST) Create(ctx genericapirequest.Context, obj runtime.Object, includeUninitialized bool) (runtime.Object, error) { func (r *REST) Create(ctx genericapirequest.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, includeUninitialized bool) (runtime.Object, error) {
tokenReview, ok := obj.(*authentication.TokenReview) tokenReview, ok := obj.(*authentication.TokenReview)
if !ok { if !ok {
return nil, apierrors.NewBadRequest(fmt.Sprintf("not a TokenReview: %#v", obj)) return nil, apierrors.NewBadRequest(fmt.Sprintf("not a TokenReview: %#v", obj))
......
...@@ -17,6 +17,7 @@ go_library( ...@@ -17,6 +17,7 @@ go_library(
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library", "//vendor/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library",
"//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library", "//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library",
"//vendor/k8s.io/apiserver/pkg/registry/rest:go_default_library",
], ],
) )
......
...@@ -23,6 +23,7 @@ import ( ...@@ -23,6 +23,7 @@ import (
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/authorization/authorizer"
genericapirequest "k8s.io/apiserver/pkg/endpoints/request" genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/registry/rest"
authorizationapi "k8s.io/kubernetes/pkg/apis/authorization" authorizationapi "k8s.io/kubernetes/pkg/apis/authorization"
authorizationvalidation "k8s.io/kubernetes/pkg/apis/authorization/validation" authorizationvalidation "k8s.io/kubernetes/pkg/apis/authorization/validation"
authorizationutil "k8s.io/kubernetes/pkg/registry/authorization/util" authorizationutil "k8s.io/kubernetes/pkg/registry/authorization/util"
...@@ -40,7 +41,7 @@ func (r *REST) New() runtime.Object { ...@@ -40,7 +41,7 @@ func (r *REST) New() runtime.Object {
return &authorizationapi.LocalSubjectAccessReview{} return &authorizationapi.LocalSubjectAccessReview{}
} }
func (r *REST) Create(ctx genericapirequest.Context, obj runtime.Object, includeUninitialized bool) (runtime.Object, error) { func (r *REST) Create(ctx genericapirequest.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, includeUninitialized bool) (runtime.Object, error) {
localSubjectAccessReview, ok := obj.(*authorizationapi.LocalSubjectAccessReview) localSubjectAccessReview, ok := obj.(*authorizationapi.LocalSubjectAccessReview)
if !ok { if !ok {
return nil, kapierrors.NewBadRequest(fmt.Sprintf("not a LocaLocalSubjectAccessReview: %#v", obj)) return nil, kapierrors.NewBadRequest(fmt.Sprintf("not a LocaLocalSubjectAccessReview: %#v", obj))
......
...@@ -17,6 +17,7 @@ go_library( ...@@ -17,6 +17,7 @@ go_library(
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library", "//vendor/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library",
"//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library", "//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library",
"//vendor/k8s.io/apiserver/pkg/registry/rest:go_default_library",
], ],
) )
......
...@@ -23,6 +23,7 @@ import ( ...@@ -23,6 +23,7 @@ import (
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/authorization/authorizer"
genericapirequest "k8s.io/apiserver/pkg/endpoints/request" genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/registry/rest"
authorizationapi "k8s.io/kubernetes/pkg/apis/authorization" authorizationapi "k8s.io/kubernetes/pkg/apis/authorization"
authorizationvalidation "k8s.io/kubernetes/pkg/apis/authorization/validation" authorizationvalidation "k8s.io/kubernetes/pkg/apis/authorization/validation"
authorizationutil "k8s.io/kubernetes/pkg/registry/authorization/util" authorizationutil "k8s.io/kubernetes/pkg/registry/authorization/util"
...@@ -40,7 +41,7 @@ func (r *REST) New() runtime.Object { ...@@ -40,7 +41,7 @@ func (r *REST) New() runtime.Object {
return &authorizationapi.SelfSubjectAccessReview{} return &authorizationapi.SelfSubjectAccessReview{}
} }
func (r *REST) Create(ctx genericapirequest.Context, obj runtime.Object, includeUninitialized bool) (runtime.Object, error) { func (r *REST) Create(ctx genericapirequest.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, includeUninitialized bool) (runtime.Object, error) {
selfSAR, ok := obj.(*authorizationapi.SelfSubjectAccessReview) selfSAR, ok := obj.(*authorizationapi.SelfSubjectAccessReview)
if !ok { if !ok {
return nil, apierrors.NewBadRequest(fmt.Sprintf("not a SelfSubjectAccessReview: %#v", obj)) return nil, apierrors.NewBadRequest(fmt.Sprintf("not a SelfSubjectAccessReview: %#v", obj))
......
...@@ -11,6 +11,7 @@ go_library( ...@@ -11,6 +11,7 @@ go_library(
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library", "//vendor/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library",
"//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library", "//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library",
"//vendor/k8s.io/apiserver/pkg/registry/rest:go_default_library",
], ],
) )
......
...@@ -23,6 +23,7 @@ import ( ...@@ -23,6 +23,7 @@ import (
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/authorization/authorizer"
genericapirequest "k8s.io/apiserver/pkg/endpoints/request" genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/registry/rest"
authorizationapi "k8s.io/kubernetes/pkg/apis/authorization" authorizationapi "k8s.io/kubernetes/pkg/apis/authorization"
) )
...@@ -42,7 +43,7 @@ func (r *REST) New() runtime.Object { ...@@ -42,7 +43,7 @@ func (r *REST) New() runtime.Object {
} }
// Create attempts to get self subject rules in specific namespace. // Create attempts to get self subject rules in specific namespace.
func (r *REST) Create(ctx genericapirequest.Context, obj runtime.Object, includeUninitialized bool) (runtime.Object, error) { func (r *REST) Create(ctx genericapirequest.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, includeUninitialized bool) (runtime.Object, error) {
selfSRR, ok := obj.(*authorizationapi.SelfSubjectRulesReview) selfSRR, ok := obj.(*authorizationapi.SelfSubjectRulesReview)
if !ok { if !ok {
return nil, apierrors.NewBadRequest(fmt.Sprintf("not a SelfSubjectRulesReview: %#v", obj)) return nil, apierrors.NewBadRequest(fmt.Sprintf("not a SelfSubjectRulesReview: %#v", obj))
......
...@@ -18,6 +18,7 @@ go_library( ...@@ -18,6 +18,7 @@ go_library(
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library", "//vendor/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library",
"//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library", "//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library",
"//vendor/k8s.io/apiserver/pkg/registry/rest:go_default_library",
], ],
) )
...@@ -44,5 +45,6 @@ go_test( ...@@ -44,5 +45,6 @@ go_test(
"//vendor/k8s.io/apiserver/pkg/authentication/user:go_default_library", "//vendor/k8s.io/apiserver/pkg/authentication/user:go_default_library",
"//vendor/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library", "//vendor/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library",
"//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library", "//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library",
"//vendor/k8s.io/apiserver/pkg/registry/rest:go_default_library",
], ],
) )
...@@ -23,6 +23,7 @@ import ( ...@@ -23,6 +23,7 @@ import (
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/authorization/authorizer"
genericapirequest "k8s.io/apiserver/pkg/endpoints/request" genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/registry/rest"
authorizationapi "k8s.io/kubernetes/pkg/apis/authorization" authorizationapi "k8s.io/kubernetes/pkg/apis/authorization"
authorizationvalidation "k8s.io/kubernetes/pkg/apis/authorization/validation" authorizationvalidation "k8s.io/kubernetes/pkg/apis/authorization/validation"
authorizationutil "k8s.io/kubernetes/pkg/registry/authorization/util" authorizationutil "k8s.io/kubernetes/pkg/registry/authorization/util"
...@@ -40,7 +41,7 @@ func (r *REST) New() runtime.Object { ...@@ -40,7 +41,7 @@ func (r *REST) New() runtime.Object {
return &authorizationapi.SubjectAccessReview{} return &authorizationapi.SubjectAccessReview{}
} }
func (r *REST) Create(ctx genericapirequest.Context, obj runtime.Object, includeUninitialized bool) (runtime.Object, error) { func (r *REST) Create(ctx genericapirequest.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, includeUninitialized bool) (runtime.Object, error) {
subjectAccessReview, ok := obj.(*authorizationapi.SubjectAccessReview) subjectAccessReview, ok := obj.(*authorizationapi.SubjectAccessReview)
if !ok { if !ok {
return nil, kapierrors.NewBadRequest(fmt.Sprintf("not a SubjectAccessReview: %#v", obj)) return nil, kapierrors.NewBadRequest(fmt.Sprintf("not a SubjectAccessReview: %#v", obj))
......
...@@ -26,6 +26,7 @@ import ( ...@@ -26,6 +26,7 @@ import (
"k8s.io/apiserver/pkg/authentication/user" "k8s.io/apiserver/pkg/authentication/user"
"k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/authorization/authorizer"
genericapirequest "k8s.io/apiserver/pkg/endpoints/request" genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/registry/rest"
authorizationapi "k8s.io/kubernetes/pkg/apis/authorization" authorizationapi "k8s.io/kubernetes/pkg/apis/authorization"
) )
...@@ -174,9 +175,9 @@ func TestCreate(t *testing.T) { ...@@ -174,9 +175,9 @@ func TestCreate(t *testing.T) {
reason: tc.reason, reason: tc.reason,
err: tc.err, err: tc.err,
} }
rest := NewREST(auth) storage := NewREST(auth)
result, err := rest.Create(genericapirequest.NewContext(), &authorizationapi.SubjectAccessReview{Spec: tc.spec}, false) result, err := storage.Create(genericapirequest.NewContext(), &authorizationapi.SubjectAccessReview{Spec: tc.spec}, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
if tc.expectedErr != "" { if tc.expectedErr != "" {
if !strings.Contains(err.Error(), tc.expectedErr) { if !strings.Contains(err.Error(), tc.expectedErr) {
......
...@@ -83,6 +83,6 @@ func (r *StatusREST) Get(ctx genericapirequest.Context, name string, options *me ...@@ -83,6 +83,6 @@ func (r *StatusREST) Get(ctx genericapirequest.Context, name string, options *me
} }
// Update alters the status subset of an object. // Update alters the status subset of an object.
func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo) return r.store.Update(ctx, name, objInfo, createValidation, updateValidation)
} }
...@@ -81,6 +81,6 @@ func (r *StatusREST) Get(ctx genericapirequest.Context, name string, options *me ...@@ -81,6 +81,6 @@ func (r *StatusREST) Get(ctx genericapirequest.Context, name string, options *me
} }
// Update alters the status subset of an object. // Update alters the status subset of an object.
func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo) return r.store.Update(ctx, name, objInfo, createValidation, updateValidation)
} }
...@@ -98,6 +98,6 @@ func (r *StatusREST) Get(ctx genericapirequest.Context, name string, options *me ...@@ -98,6 +98,6 @@ func (r *StatusREST) Get(ctx genericapirequest.Context, name string, options *me
} }
// Update alters the status subset of an object. // Update alters the status subset of an object.
func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo) return r.store.Update(ctx, name, objInfo, createValidation, updateValidation)
} }
...@@ -28,8 +28,8 @@ import ( ...@@ -28,8 +28,8 @@ import (
// Registry is an interface for things that know how to store CSRs. // Registry is an interface for things that know how to store CSRs.
type Registry interface { type Registry interface {
ListCSRs(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*certificates.CertificateSigningRequestList, error) ListCSRs(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*certificates.CertificateSigningRequestList, error)
CreateCSR(ctx genericapirequest.Context, csr *certificates.CertificateSigningRequest) error CreateCSR(ctx genericapirequest.Context, csr *certificates.CertificateSigningRequest, createValidation rest.ValidateObjectFunc) error
UpdateCSR(ctx genericapirequest.Context, csr *certificates.CertificateSigningRequest) error UpdateCSR(ctx genericapirequest.Context, csr *certificates.CertificateSigningRequest, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) error
GetCSR(ctx genericapirequest.Context, csrID string, options *metav1.GetOptions) (*certificates.CertificateSigningRequest, error) GetCSR(ctx genericapirequest.Context, csrID string, options *metav1.GetOptions) (*certificates.CertificateSigningRequest, error)
DeleteCSR(ctx genericapirequest.Context, csrID string) error DeleteCSR(ctx genericapirequest.Context, csrID string) error
WatchCSRs(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error) WatchCSRs(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error)
...@@ -55,13 +55,13 @@ func (s *storage) ListCSRs(ctx genericapirequest.Context, options *metainternalv ...@@ -55,13 +55,13 @@ func (s *storage) ListCSRs(ctx genericapirequest.Context, options *metainternalv
return obj.(*certificates.CertificateSigningRequestList), nil return obj.(*certificates.CertificateSigningRequestList), nil
} }
func (s *storage) CreateCSR(ctx genericapirequest.Context, csr *certificates.CertificateSigningRequest) error { func (s *storage) CreateCSR(ctx genericapirequest.Context, csr *certificates.CertificateSigningRequest, createValidation rest.ValidateObjectFunc) error {
_, err := s.Create(ctx, csr, false) _, err := s.Create(ctx, csr, createValidation, false)
return err return err
} }
func (s *storage) UpdateCSR(ctx genericapirequest.Context, csr *certificates.CertificateSigningRequest) error { func (s *storage) UpdateCSR(ctx genericapirequest.Context, csr *certificates.CertificateSigningRequest, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) error {
_, _, err := s.Update(ctx, csr.Name, rest.DefaultUpdatedObjectInfo(csr)) _, _, err := s.Update(ctx, csr.Name, rest.DefaultUpdatedObjectInfo(csr), createValidation, updateValidation)
return err return err
} }
......
...@@ -78,8 +78,8 @@ func (r *StatusREST) New() runtime.Object { ...@@ -78,8 +78,8 @@ func (r *StatusREST) New() runtime.Object {
} }
// Update alters the status subset of an object. // Update alters the status subset of an object.
func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo) return r.store.Update(ctx, name, objInfo, createValidation, updateValidation)
} }
// ApprovalREST implements the REST endpoint for changing the approval state of a CSR. // ApprovalREST implements the REST endpoint for changing the approval state of a CSR.
...@@ -92,6 +92,6 @@ func (r *ApprovalREST) New() runtime.Object { ...@@ -92,6 +92,6 @@ func (r *ApprovalREST) New() runtime.Object {
} }
// Update alters the approval subset of an object. // Update alters the approval subset of an object.
func (r *ApprovalREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { func (r *ApprovalREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo) return r.store.Update(ctx, name, objInfo, createValidation, updateValidation)
} }
...@@ -30,8 +30,8 @@ type Registry interface { ...@@ -30,8 +30,8 @@ type Registry interface {
ListConfigMaps(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*api.ConfigMapList, error) ListConfigMaps(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*api.ConfigMapList, error)
WatchConfigMaps(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error) WatchConfigMaps(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error)
GetConfigMap(ctx genericapirequest.Context, name string, options *metav1.GetOptions) (*api.ConfigMap, error) GetConfigMap(ctx genericapirequest.Context, name string, options *metav1.GetOptions) (*api.ConfigMap, error)
CreateConfigMap(ctx genericapirequest.Context, cfg *api.ConfigMap) (*api.ConfigMap, error) CreateConfigMap(ctx genericapirequest.Context, cfg *api.ConfigMap, createValidation rest.ValidateObjectFunc) (*api.ConfigMap, error)
UpdateConfigMap(ctx genericapirequest.Context, cfg *api.ConfigMap) (*api.ConfigMap, error) UpdateConfigMap(ctx genericapirequest.Context, cfg *api.ConfigMap, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (*api.ConfigMap, error)
DeleteConfigMap(ctx genericapirequest.Context, name string) error DeleteConfigMap(ctx genericapirequest.Context, name string) error
} }
...@@ -68,8 +68,8 @@ func (s *storage) GetConfigMap(ctx genericapirequest.Context, name string, optio ...@@ -68,8 +68,8 @@ func (s *storage) GetConfigMap(ctx genericapirequest.Context, name string, optio
return obj.(*api.ConfigMap), nil return obj.(*api.ConfigMap), nil
} }
func (s *storage) CreateConfigMap(ctx genericapirequest.Context, cfg *api.ConfigMap) (*api.ConfigMap, error) { func (s *storage) CreateConfigMap(ctx genericapirequest.Context, cfg *api.ConfigMap, createValidation rest.ValidateObjectFunc) (*api.ConfigMap, error) {
obj, err := s.Create(ctx, cfg, false) obj, err := s.Create(ctx, cfg, createValidation, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -77,8 +77,8 @@ func (s *storage) CreateConfigMap(ctx genericapirequest.Context, cfg *api.Config ...@@ -77,8 +77,8 @@ func (s *storage) CreateConfigMap(ctx genericapirequest.Context, cfg *api.Config
return obj.(*api.ConfigMap), nil return obj.(*api.ConfigMap), nil
} }
func (s *storage) UpdateConfigMap(ctx genericapirequest.Context, cfg *api.ConfigMap) (*api.ConfigMap, error) { func (s *storage) UpdateConfigMap(ctx genericapirequest.Context, cfg *api.ConfigMap, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (*api.ConfigMap, error) {
obj, _, err := s.Update(ctx, cfg.Name, rest.DefaultUpdatedObjectInfo(cfg)) obj, _, err := s.Update(ctx, cfg.Name, rest.DefaultUpdatedObjectInfo(cfg), createValidation, updateValidation)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -30,7 +30,7 @@ type Registry interface { ...@@ -30,7 +30,7 @@ type Registry interface {
ListEndpoints(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*api.EndpointsList, error) ListEndpoints(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*api.EndpointsList, error)
GetEndpoints(ctx genericapirequest.Context, name string, options *metav1.GetOptions) (*api.Endpoints, error) GetEndpoints(ctx genericapirequest.Context, name string, options *metav1.GetOptions) (*api.Endpoints, error)
WatchEndpoints(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error) WatchEndpoints(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error)
UpdateEndpoints(ctx genericapirequest.Context, e *api.Endpoints) error UpdateEndpoints(ctx genericapirequest.Context, e *api.Endpoints, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) error
DeleteEndpoints(ctx genericapirequest.Context, name string) error DeleteEndpoints(ctx genericapirequest.Context, name string) error
} }
...@@ -65,8 +65,8 @@ func (s *storage) GetEndpoints(ctx genericapirequest.Context, name string, optio ...@@ -65,8 +65,8 @@ func (s *storage) GetEndpoints(ctx genericapirequest.Context, name string, optio
return obj.(*api.Endpoints), nil return obj.(*api.Endpoints), nil
} }
func (s *storage) UpdateEndpoints(ctx genericapirequest.Context, endpoints *api.Endpoints) error { func (s *storage) UpdateEndpoints(ctx genericapirequest.Context, endpoints *api.Endpoints, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) error {
_, _, err := s.Update(ctx, endpoints.Name, rest.DefaultUpdatedObjectInfo(endpoints)) _, _, err := s.Update(ctx, endpoints.Name, rest.DefaultUpdatedObjectInfo(endpoints), createValidation, updateValidation)
return err return err
} }
......
...@@ -30,8 +30,8 @@ type Registry interface { ...@@ -30,8 +30,8 @@ type Registry interface {
ListNamespaces(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*api.NamespaceList, error) ListNamespaces(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*api.NamespaceList, error)
WatchNamespaces(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error) WatchNamespaces(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error)
GetNamespace(ctx genericapirequest.Context, namespaceID string, options *metav1.GetOptions) (*api.Namespace, error) GetNamespace(ctx genericapirequest.Context, namespaceID string, options *metav1.GetOptions) (*api.Namespace, error)
CreateNamespace(ctx genericapirequest.Context, namespace *api.Namespace) error CreateNamespace(ctx genericapirequest.Context, namespace *api.Namespace, createValidation rest.ValidateObjectFunc) error
UpdateNamespace(ctx genericapirequest.Context, namespace *api.Namespace) error UpdateNamespace(ctx genericapirequest.Context, namespace *api.Namespace, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) error
DeleteNamespace(ctx genericapirequest.Context, namespaceID string) error DeleteNamespace(ctx genericapirequest.Context, namespaceID string) error
} }
...@@ -66,13 +66,13 @@ func (s *storage) GetNamespace(ctx genericapirequest.Context, namespaceName stri ...@@ -66,13 +66,13 @@ func (s *storage) GetNamespace(ctx genericapirequest.Context, namespaceName stri
return obj.(*api.Namespace), nil return obj.(*api.Namespace), nil
} }
func (s *storage) CreateNamespace(ctx genericapirequest.Context, namespace *api.Namespace) error { func (s *storage) CreateNamespace(ctx genericapirequest.Context, namespace *api.Namespace, createValidation rest.ValidateObjectFunc) error {
_, err := s.Create(ctx, namespace, false) _, err := s.Create(ctx, namespace, createValidation, false)
return err return err
} }
func (s *storage) UpdateNamespace(ctx genericapirequest.Context, namespace *api.Namespace) error { func (s *storage) UpdateNamespace(ctx genericapirequest.Context, namespace *api.Namespace, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) error {
_, _, err := s.Update(ctx, namespace.Name, rest.DefaultUpdatedObjectInfo(namespace)) _, _, err := s.Update(ctx, namespace.Name, rest.DefaultUpdatedObjectInfo(namespace), createValidation, updateValidation)
return err return err
} }
......
...@@ -19,6 +19,7 @@ go_test( ...@@ -19,6 +19,7 @@ go_test(
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library", "//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
"//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library", "//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library",
"//vendor/k8s.io/apiserver/pkg/registry/generic:go_default_library", "//vendor/k8s.io/apiserver/pkg/registry/generic:go_default_library",
"//vendor/k8s.io/apiserver/pkg/registry/rest:go_default_library",
"//vendor/k8s.io/apiserver/pkg/storage/etcd/testing:go_default_library", "//vendor/k8s.io/apiserver/pkg/storage/etcd/testing:go_default_library",
], ],
) )
......
...@@ -89,12 +89,12 @@ func (r *REST) List(ctx genericapirequest.Context, options *metainternalversion. ...@@ -89,12 +89,12 @@ func (r *REST) List(ctx genericapirequest.Context, options *metainternalversion.
return r.store.List(ctx, options) return r.store.List(ctx, options)
} }
func (r *REST) Create(ctx genericapirequest.Context, obj runtime.Object, includeUninitialized bool) (runtime.Object, error) { func (r *REST) Create(ctx genericapirequest.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, includeUninitialized bool) (runtime.Object, error) {
return r.store.Create(ctx, obj, includeUninitialized) return r.store.Create(ctx, obj, createValidation, includeUninitialized)
} }
func (r *REST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { func (r *REST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo) return r.store.Update(ctx, name, objInfo, createValidation, updateValidation)
} }
func (r *REST) Get(ctx genericapirequest.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { func (r *REST) Get(ctx genericapirequest.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
...@@ -219,8 +219,8 @@ func (r *StatusREST) Get(ctx genericapirequest.Context, name string, options *me ...@@ -219,8 +219,8 @@ func (r *StatusREST) Get(ctx genericapirequest.Context, name string, options *me
} }
// Update alters the status subset of an object. // Update alters the status subset of an object.
func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo) return r.store.Update(ctx, name, objInfo, createValidation, updateValidation)
} }
func (r *FinalizeREST) New() runtime.Object { func (r *FinalizeREST) New() runtime.Object {
...@@ -228,6 +228,6 @@ func (r *FinalizeREST) New() runtime.Object { ...@@ -228,6 +228,6 @@ func (r *FinalizeREST) New() runtime.Object {
} }
// Update alters the status finalizers subset of an object. // Update alters the status finalizers subset of an object.
func (r *FinalizeREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { func (r *FinalizeREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo) return r.store.Update(ctx, name, objInfo, createValidation, updateValidation)
} }
...@@ -24,6 +24,7 @@ import ( ...@@ -24,6 +24,7 @@ import (
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
genericapirequest "k8s.io/apiserver/pkg/endpoints/request" genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/generic"
"k8s.io/apiserver/pkg/registry/rest"
etcdtesting "k8s.io/apiserver/pkg/storage/etcd/testing" etcdtesting "k8s.io/apiserver/pkg/storage/etcd/testing"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/registry/registrytest" "k8s.io/kubernetes/pkg/registry/registrytest"
...@@ -67,7 +68,7 @@ func TestCreateSetsFields(t *testing.T) { ...@@ -67,7 +68,7 @@ func TestCreateSetsFields(t *testing.T) {
defer storage.store.DestroyFunc() defer storage.store.DestroyFunc()
namespace := validNewNamespace() namespace := validNewNamespace()
ctx := genericapirequest.NewContext() ctx := genericapirequest.NewContext()
_, err := storage.Create(ctx, namespace, false) _, err := storage.Create(ctx, namespace, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
......
...@@ -28,8 +28,8 @@ import ( ...@@ -28,8 +28,8 @@ import (
// Registry is an interface for things that know how to store node. // Registry is an interface for things that know how to store node.
type Registry interface { type Registry interface {
ListNodes(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*api.NodeList, error) ListNodes(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*api.NodeList, error)
CreateNode(ctx genericapirequest.Context, node *api.Node) error CreateNode(ctx genericapirequest.Context, node *api.Node, createValidation rest.ValidateObjectFunc) error
UpdateNode(ctx genericapirequest.Context, node *api.Node) error UpdateNode(ctx genericapirequest.Context, node *api.Node, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) error
GetNode(ctx genericapirequest.Context, nodeID string, options *metav1.GetOptions) (*api.Node, error) GetNode(ctx genericapirequest.Context, nodeID string, options *metav1.GetOptions) (*api.Node, error)
DeleteNode(ctx genericapirequest.Context, nodeID string) error DeleteNode(ctx genericapirequest.Context, nodeID string) error
WatchNodes(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error) WatchNodes(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error)
...@@ -55,13 +55,13 @@ func (s *storage) ListNodes(ctx genericapirequest.Context, options *metainternal ...@@ -55,13 +55,13 @@ func (s *storage) ListNodes(ctx genericapirequest.Context, options *metainternal
return obj.(*api.NodeList), nil return obj.(*api.NodeList), nil
} }
func (s *storage) CreateNode(ctx genericapirequest.Context, node *api.Node) error { func (s *storage) CreateNode(ctx genericapirequest.Context, node *api.Node, createValidation rest.ValidateObjectFunc) error {
_, err := s.Create(ctx, node, false) _, err := s.Create(ctx, node, createValidation, false)
return err return err
} }
func (s *storage) UpdateNode(ctx genericapirequest.Context, node *api.Node) error { func (s *storage) UpdateNode(ctx genericapirequest.Context, node *api.Node, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) error {
_, _, err := s.Update(ctx, node.Name, rest.DefaultUpdatedObjectInfo(node)) _, _, err := s.Update(ctx, node.Name, rest.DefaultUpdatedObjectInfo(node), createValidation, updateValidation)
return err return err
} }
......
...@@ -68,8 +68,8 @@ func (r *StatusREST) Get(ctx genericapirequest.Context, name string, options *me ...@@ -68,8 +68,8 @@ func (r *StatusREST) Get(ctx genericapirequest.Context, name string, options *me
} }
// Update alters the status subset of an object. // Update alters the status subset of an object.
func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo) return r.store.Update(ctx, name, objInfo, createValidation, updateValidation)
} }
// NewStorage returns a NodeStorage object that will work against nodes. // NewStorage returns a NodeStorage object that will work against nodes.
......
...@@ -78,6 +78,6 @@ func (r *StatusREST) Get(ctx genericapirequest.Context, name string, options *me ...@@ -78,6 +78,6 @@ func (r *StatusREST) Get(ctx genericapirequest.Context, name string, options *me
} }
// Update alters the status subset of an object. // Update alters the status subset of an object.
func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo) return r.store.Update(ctx, name, objInfo, createValidation, updateValidation)
} }
...@@ -187,7 +187,7 @@ func TestUpdateStatus(t *testing.T) { ...@@ -187,7 +187,7 @@ func TestUpdateStatus(t *testing.T) {
}, },
} }
_, _, err = statusStorage.Update(ctx, pvIn.Name, rest.DefaultUpdatedObjectInfo(pvIn)) _, _, err = statusStorage.Update(ctx, pvIn.Name, rest.DefaultUpdatedObjectInfo(pvIn), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if err != nil { if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
......
...@@ -78,6 +78,6 @@ func (r *StatusREST) Get(ctx genericapirequest.Context, name string, options *me ...@@ -78,6 +78,6 @@ func (r *StatusREST) Get(ctx genericapirequest.Context, name string, options *me
} }
// Update alters the status subset of an object. // Update alters the status subset of an object.
func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo) return r.store.Update(ctx, name, objInfo, createValidation, updateValidation)
} }
...@@ -178,7 +178,7 @@ func TestUpdateStatus(t *testing.T) { ...@@ -178,7 +178,7 @@ func TestUpdateStatus(t *testing.T) {
}, },
} }
_, _, err = statusStorage.Update(ctx, pvc.Name, rest.DefaultUpdatedObjectInfo(pvc)) _, _, err = statusStorage.Update(ctx, pvc.Name, rest.DefaultUpdatedObjectInfo(pvc), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if err != nil { if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
......
...@@ -78,7 +78,7 @@ func (r *EvictionREST) New() runtime.Object { ...@@ -78,7 +78,7 @@ func (r *EvictionREST) New() runtime.Object {
} }
// Create attempts to create a new eviction. That is, it tries to evict a pod. // Create attempts to create a new eviction. That is, it tries to evict a pod.
func (r *EvictionREST) Create(ctx genericapirequest.Context, obj runtime.Object, includeUninitialized bool) (runtime.Object, error) { func (r *EvictionREST) Create(ctx genericapirequest.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, includeUninitialized bool) (runtime.Object, error) {
eviction := obj.(*policy.Eviction) eviction := obj.(*policy.Eviction)
obj, err := r.store.Get(ctx, eviction.Name, &metav1.GetOptions{}) obj, err := r.store.Get(ctx, eviction.Name, &metav1.GetOptions{})
......
...@@ -135,7 +135,7 @@ func (r *BindingREST) New() runtime.Object { ...@@ -135,7 +135,7 @@ func (r *BindingREST) New() runtime.Object {
var _ = rest.Creater(&BindingREST{}) var _ = rest.Creater(&BindingREST{})
// Create ensures a pod is bound to a specific host. // Create ensures a pod is bound to a specific host.
func (r *BindingREST) Create(ctx genericapirequest.Context, obj runtime.Object, includeUninitialized bool) (out runtime.Object, err error) { func (r *BindingREST) Create(ctx genericapirequest.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, includeUninitialized bool) (out runtime.Object, err error) {
binding := obj.(*api.Binding) binding := obj.(*api.Binding)
// TODO: move me to a binding strategy // TODO: move me to a binding strategy
...@@ -212,6 +212,6 @@ func (r *StatusREST) Get(ctx genericapirequest.Context, name string, options *me ...@@ -212,6 +212,6 @@ func (r *StatusREST) Get(ctx genericapirequest.Context, name string, options *me
} }
// Update alters the status subset of an object. // Update alters the status subset of an object.
func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo) return r.store.Update(ctx, name, objInfo, createValidation, updateValidation)
} }
...@@ -188,7 +188,7 @@ func TestIgnoreDeleteNotFound(t *testing.T) { ...@@ -188,7 +188,7 @@ func TestIgnoreDeleteNotFound(t *testing.T) {
} }
// create pod // create pod
_, err = registry.Create(testContext, pod, false) _, err = registry.Create(testContext, pod, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
...@@ -225,7 +225,7 @@ func TestCreateSetsFields(t *testing.T) { ...@@ -225,7 +225,7 @@ func TestCreateSetsFields(t *testing.T) {
defer server.Terminate(t) defer server.Terminate(t)
defer storage.Store.DestroyFunc() defer storage.Store.DestroyFunc()
pod := validNewPod() pod := validNewPod()
_, err := storage.Create(genericapirequest.NewDefaultContext(), pod, false) _, err := storage.Create(genericapirequest.NewDefaultContext(), pod, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
...@@ -489,7 +489,7 @@ func TestEtcdCreate(t *testing.T) { ...@@ -489,7 +489,7 @@ func TestEtcdCreate(t *testing.T) {
defer server.Terminate(t) defer server.Terminate(t)
defer storage.Store.DestroyFunc() defer storage.Store.DestroyFunc()
ctx := genericapirequest.NewDefaultContext() ctx := genericapirequest.NewDefaultContext()
_, err := storage.Create(ctx, validNewPod(), false) _, err := storage.Create(ctx, validNewPod(), rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
...@@ -498,7 +498,7 @@ func TestEtcdCreate(t *testing.T) { ...@@ -498,7 +498,7 @@ func TestEtcdCreate(t *testing.T) {
_, err = bindingStorage.Create(ctx, &api.Binding{ _, err = bindingStorage.Create(ctx, &api.Binding{
ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceDefault, Name: "foo"}, ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceDefault, Name: "foo"},
Target: api.ObjectReference{Name: "machine"}, Target: api.ObjectReference{Name: "machine"},
}, false) }, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
...@@ -524,7 +524,7 @@ func TestEtcdCreateBindingNoPod(t *testing.T) { ...@@ -524,7 +524,7 @@ func TestEtcdCreateBindingNoPod(t *testing.T) {
_, err := bindingStorage.Create(ctx, &api.Binding{ _, err := bindingStorage.Create(ctx, &api.Binding{
ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceDefault, Name: "foo"}, ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceDefault, Name: "foo"},
Target: api.ObjectReference{Name: "machine"}, Target: api.ObjectReference{Name: "machine"},
}, false) }, rest.ValidateAllObjectFunc, false)
if err == nil { if err == nil {
t.Fatalf("Expected not-found-error but got nothing") t.Fatalf("Expected not-found-error but got nothing")
} }
...@@ -547,7 +547,7 @@ func TestEtcdCreateFailsWithoutNamespace(t *testing.T) { ...@@ -547,7 +547,7 @@ func TestEtcdCreateFailsWithoutNamespace(t *testing.T) {
defer storage.Store.DestroyFunc() defer storage.Store.DestroyFunc()
pod := validNewPod() pod := validNewPod()
pod.Namespace = "" pod.Namespace = ""
_, err := storage.Create(genericapirequest.NewContext(), pod, false) _, err := storage.Create(genericapirequest.NewContext(), pod, rest.ValidateAllObjectFunc, false)
// Accept "namespace" or "Namespace". // Accept "namespace" or "Namespace".
if err == nil || !strings.Contains(err.Error(), "amespace") { if err == nil || !strings.Contains(err.Error(), "amespace") {
t.Fatalf("expected error that namespace was missing from context, got: %v", err) t.Fatalf("expected error that namespace was missing from context, got: %v", err)
...@@ -559,7 +559,7 @@ func TestEtcdCreateWithContainersNotFound(t *testing.T) { ...@@ -559,7 +559,7 @@ func TestEtcdCreateWithContainersNotFound(t *testing.T) {
defer server.Terminate(t) defer server.Terminate(t)
defer storage.Store.DestroyFunc() defer storage.Store.DestroyFunc()
ctx := genericapirequest.NewDefaultContext() ctx := genericapirequest.NewDefaultContext()
_, err := storage.Create(ctx, validNewPod(), false) _, err := storage.Create(ctx, validNewPod(), rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
...@@ -572,7 +572,7 @@ func TestEtcdCreateWithContainersNotFound(t *testing.T) { ...@@ -572,7 +572,7 @@ func TestEtcdCreateWithContainersNotFound(t *testing.T) {
Annotations: map[string]string{"label1": "value1"}, Annotations: map[string]string{"label1": "value1"},
}, },
Target: api.ObjectReference{Name: "machine"}, Target: api.ObjectReference{Name: "machine"},
}, false) }, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
...@@ -594,7 +594,7 @@ func TestEtcdCreateWithConflict(t *testing.T) { ...@@ -594,7 +594,7 @@ func TestEtcdCreateWithConflict(t *testing.T) {
defer storage.Store.DestroyFunc() defer storage.Store.DestroyFunc()
ctx := genericapirequest.NewDefaultContext() ctx := genericapirequest.NewDefaultContext()
_, err := storage.Create(ctx, validNewPod(), false) _, err := storage.Create(ctx, validNewPod(), rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
...@@ -608,12 +608,12 @@ func TestEtcdCreateWithConflict(t *testing.T) { ...@@ -608,12 +608,12 @@ func TestEtcdCreateWithConflict(t *testing.T) {
}, },
Target: api.ObjectReference{Name: "machine"}, Target: api.ObjectReference{Name: "machine"},
} }
_, err = bindingStorage.Create(ctx, &binding, false) _, err = bindingStorage.Create(ctx, &binding, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
_, err = bindingStorage.Create(ctx, &binding, false) _, err = bindingStorage.Create(ctx, &binding, rest.ValidateAllObjectFunc, false)
if err == nil || !errors.IsConflict(err) { if err == nil || !errors.IsConflict(err) {
t.Fatalf("expected resource conflict error, not: %v", err) t.Fatalf("expected resource conflict error, not: %v", err)
} }
...@@ -624,7 +624,7 @@ func TestEtcdCreateWithExistingContainers(t *testing.T) { ...@@ -624,7 +624,7 @@ func TestEtcdCreateWithExistingContainers(t *testing.T) {
defer server.Terminate(t) defer server.Terminate(t)
defer storage.Store.DestroyFunc() defer storage.Store.DestroyFunc()
ctx := genericapirequest.NewDefaultContext() ctx := genericapirequest.NewDefaultContext()
_, err := storage.Create(ctx, validNewPod(), false) _, err := storage.Create(ctx, validNewPod(), rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
...@@ -633,7 +633,7 @@ func TestEtcdCreateWithExistingContainers(t *testing.T) { ...@@ -633,7 +633,7 @@ func TestEtcdCreateWithExistingContainers(t *testing.T) {
_, err = bindingStorage.Create(ctx, &api.Binding{ _, err = bindingStorage.Create(ctx, &api.Binding{
ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceDefault, Name: "foo"}, ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceDefault, Name: "foo"},
Target: api.ObjectReference{Name: "machine"}, Target: api.ObjectReference{Name: "machine"},
}, false) }, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
...@@ -683,10 +683,10 @@ func TestEtcdCreateBinding(t *testing.T) { ...@@ -683,10 +683,10 @@ func TestEtcdCreateBinding(t *testing.T) {
for k, test := range testCases { for k, test := range testCases {
storage, bindingStorage, _, server := newStorage(t) storage, bindingStorage, _, server := newStorage(t)
if _, err := storage.Create(ctx, validNewPod(), false); err != nil { if _, err := storage.Create(ctx, validNewPod(), rest.ValidateAllObjectFunc, false); err != nil {
t.Fatalf("%s: unexpected error: %v", k, err) t.Fatalf("%s: unexpected error: %v", k, err)
} }
if _, err := bindingStorage.Create(ctx, &test.binding, false); !test.errOK(err) { if _, err := bindingStorage.Create(ctx, &test.binding, rest.ValidateAllObjectFunc, false); !test.errOK(err) {
t.Errorf("%s: unexpected error: %v", k, err) t.Errorf("%s: unexpected error: %v", k, err)
} else if err == nil { } else if err == nil {
// If bind succeeded, verify Host field in pod's Spec. // If bind succeeded, verify Host field in pod's Spec.
...@@ -712,7 +712,7 @@ func TestEtcdUpdateUninitialized(t *testing.T) { ...@@ -712,7 +712,7 @@ func TestEtcdUpdateUninitialized(t *testing.T) {
pod := validNewPod() pod := validNewPod()
// add pending initializers to the pod // add pending initializers to the pod
pod.ObjectMeta.Initializers = &metav1.Initializers{Pending: []metav1.Initializer{{Name: "init.k8s.io"}}} pod.ObjectMeta.Initializers = &metav1.Initializers{Pending: []metav1.Initializer{{Name: "init.k8s.io"}}}
if _, err := storage.Create(ctx, pod, true); err != nil { if _, err := storage.Create(ctx, pod, rest.ValidateAllObjectFunc, true); err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
podIn := *pod podIn := *pod
...@@ -727,7 +727,7 @@ func TestEtcdUpdateUninitialized(t *testing.T) { ...@@ -727,7 +727,7 @@ func TestEtcdUpdateUninitialized(t *testing.T) {
}) })
podIn.ObjectMeta.Initializers = nil podIn.ObjectMeta.Initializers = nil
_, _, err := storage.Update(ctx, podIn.Name, rest.DefaultUpdatedObjectInfo(&podIn)) _, _, err := storage.Update(ctx, podIn.Name, rest.DefaultUpdatedObjectInfo(&podIn), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if err != nil { if err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
...@@ -754,7 +754,7 @@ func TestEtcdStatusUpdateUninitialized(t *testing.T) { ...@@ -754,7 +754,7 @@ func TestEtcdStatusUpdateUninitialized(t *testing.T) {
pod := validNewPod() pod := validNewPod()
// add pending initializers to the pod // add pending initializers to the pod
pod.ObjectMeta.Initializers = &metav1.Initializers{Pending: []metav1.Initializer{{Name: "init.k8s.io"}}} pod.ObjectMeta.Initializers = &metav1.Initializers{Pending: []metav1.Initializer{{Name: "init.k8s.io"}}}
if _, err := storage.Create(ctx, pod, true); err != nil { if _, err := storage.Create(ctx, pod, rest.ValidateAllObjectFunc, true); err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
podIn := *pod podIn := *pod
...@@ -762,7 +762,7 @@ func TestEtcdStatusUpdateUninitialized(t *testing.T) { ...@@ -762,7 +762,7 @@ func TestEtcdStatusUpdateUninitialized(t *testing.T) {
podIn.Status.Phase = api.PodRunning podIn.Status.Phase = api.PodRunning
podIn.ObjectMeta.Initializers = nil podIn.ObjectMeta.Initializers = nil
_, _, err := statusStorage.Update(ctx, podIn.Name, rest.DefaultUpdatedObjectInfo(&podIn)) _, _, err := statusStorage.Update(ctx, podIn.Name, rest.DefaultUpdatedObjectInfo(&podIn), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
expected := "Forbidden: must not update status when the object is uninitialized" expected := "Forbidden: must not update status when the object is uninitialized"
if err == nil { if err == nil {
t.Fatalf("Unexpected no err, expected %q", expected) t.Fatalf("Unexpected no err, expected %q", expected)
...@@ -778,12 +778,12 @@ func TestEtcdUpdateNotScheduled(t *testing.T) { ...@@ -778,12 +778,12 @@ func TestEtcdUpdateNotScheduled(t *testing.T) {
defer storage.Store.DestroyFunc() defer storage.Store.DestroyFunc()
ctx := genericapirequest.NewDefaultContext() ctx := genericapirequest.NewDefaultContext()
if _, err := storage.Create(ctx, validNewPod(), false); err != nil { if _, err := storage.Create(ctx, validNewPod(), rest.ValidateAllObjectFunc, false); err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
podIn := validChangedPod() podIn := validChangedPod()
_, _, err := storage.Update(ctx, podIn.Name, rest.DefaultUpdatedObjectInfo(podIn)) _, _, err := storage.Update(ctx, podIn.Name, rest.DefaultUpdatedObjectInfo(podIn), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if err != nil { if err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
...@@ -853,7 +853,7 @@ func TestEtcdUpdateScheduled(t *testing.T) { ...@@ -853,7 +853,7 @@ func TestEtcdUpdateScheduled(t *testing.T) {
SchedulerName: api.DefaultSchedulerName, SchedulerName: api.DefaultSchedulerName,
}, },
} }
_, _, err = storage.Update(ctx, podIn.Name, rest.DefaultUpdatedObjectInfo(&podIn)) _, _, err = storage.Update(ctx, podIn.Name, rest.DefaultUpdatedObjectInfo(&podIn), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if err != nil { if err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
...@@ -937,7 +937,7 @@ func TestEtcdUpdateStatus(t *testing.T) { ...@@ -937,7 +937,7 @@ func TestEtcdUpdateStatus(t *testing.T) {
expected.Labels = podIn.Labels expected.Labels = podIn.Labels
expected.Status = podIn.Status expected.Status = podIn.Status
_, _, err = statusStorage.Update(ctx, podIn.Name, rest.DefaultUpdatedObjectInfo(&podIn)) _, _, err = statusStorage.Update(ctx, podIn.Name, rest.DefaultUpdatedObjectInfo(&podIn), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if err != nil { if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
......
...@@ -34,8 +34,8 @@ type Registry interface { ...@@ -34,8 +34,8 @@ type Registry interface {
ListControllers(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*api.ReplicationControllerList, error) ListControllers(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*api.ReplicationControllerList, error)
WatchControllers(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error) WatchControllers(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error)
GetController(ctx genericapirequest.Context, controllerID string, options *metav1.GetOptions) (*api.ReplicationController, error) GetController(ctx genericapirequest.Context, controllerID string, options *metav1.GetOptions) (*api.ReplicationController, error)
CreateController(ctx genericapirequest.Context, controller *api.ReplicationController) (*api.ReplicationController, error) CreateController(ctx genericapirequest.Context, controller *api.ReplicationController, createValidation rest.ValidateObjectFunc) (*api.ReplicationController, error)
UpdateController(ctx genericapirequest.Context, controller *api.ReplicationController) (*api.ReplicationController, error) UpdateController(ctx genericapirequest.Context, controller *api.ReplicationController, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (*api.ReplicationController, error)
DeleteController(ctx genericapirequest.Context, controllerID string) error DeleteController(ctx genericapirequest.Context, controllerID string) error
} }
...@@ -73,16 +73,16 @@ func (s *storage) GetController(ctx genericapirequest.Context, controllerID stri ...@@ -73,16 +73,16 @@ func (s *storage) GetController(ctx genericapirequest.Context, controllerID stri
return obj.(*api.ReplicationController), nil return obj.(*api.ReplicationController), nil
} }
func (s *storage) CreateController(ctx genericapirequest.Context, controller *api.ReplicationController) (*api.ReplicationController, error) { func (s *storage) CreateController(ctx genericapirequest.Context, controller *api.ReplicationController, createValidation rest.ValidateObjectFunc) (*api.ReplicationController, error) {
obj, err := s.Create(ctx, controller, false) obj, err := s.Create(ctx, controller, createValidation, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return obj.(*api.ReplicationController), nil return obj.(*api.ReplicationController), nil
} }
func (s *storage) UpdateController(ctx genericapirequest.Context, controller *api.ReplicationController) (*api.ReplicationController, error) { func (s *storage) UpdateController(ctx genericapirequest.Context, controller *api.ReplicationController, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (*api.ReplicationController, error) {
obj, _, err := s.Update(ctx, controller.Name, rest.DefaultUpdatedObjectInfo(controller)) obj, _, err := s.Update(ctx, controller.Name, rest.DefaultUpdatedObjectInfo(controller), createValidation, updateValidation)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -119,8 +119,8 @@ func (r *StatusREST) Get(ctx genericapirequest.Context, name string, options *me ...@@ -119,8 +119,8 @@ func (r *StatusREST) Get(ctx genericapirequest.Context, name string, options *me
} }
// Update alters the status subset of an object. // Update alters the status subset of an object.
func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo) return r.store.Update(ctx, name, objInfo, createValidation, updateValidation)
} }
type ScaleREST struct { type ScaleREST struct {
...@@ -153,13 +153,14 @@ func (r *ScaleREST) Get(ctx genericapirequest.Context, name string, options *met ...@@ -153,13 +153,14 @@ func (r *ScaleREST) Get(ctx genericapirequest.Context, name string, options *met
return scaleFromRC(rc), nil return scaleFromRC(rc), nil
} }
func (r *ScaleREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { func (r *ScaleREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
rc, err := r.registry.GetController(ctx, name, &metav1.GetOptions{}) rc, err := r.registry.GetController(ctx, name, &metav1.GetOptions{})
if err != nil { if err != nil {
return nil, false, errors.NewNotFound(autoscaling.Resource("replicationcontrollers/scale"), name) return nil, false, errors.NewNotFound(autoscaling.Resource("replicationcontrollers/scale"), name)
} }
oldScale := scaleFromRC(rc) oldScale := scaleFromRC(rc)
// TODO: should this pass validation?
obj, err := objInfo.UpdatedObject(ctx, oldScale) obj, err := objInfo.UpdatedObject(ctx, oldScale)
if err != nil { if err != nil {
return nil, false, err return nil, false, err
...@@ -179,7 +180,7 @@ func (r *ScaleREST) Update(ctx genericapirequest.Context, name string, objInfo r ...@@ -179,7 +180,7 @@ func (r *ScaleREST) Update(ctx genericapirequest.Context, name string, objInfo r
rc.Spec.Replicas = scale.Spec.Replicas rc.Spec.Replicas = scale.Spec.Replicas
rc.ResourceVersion = scale.ResourceVersion rc.ResourceVersion = scale.ResourceVersion
rc, err = r.registry.UpdateController(ctx, rc) rc, err = r.registry.UpdateController(ctx, rc, createValidation, updateValidation)
if err != nil { if err != nil {
return nil, false, err return nil, false, err
} }
......
...@@ -55,7 +55,7 @@ func newStorage(t *testing.T) (ControllerStorage, *etcdtesting.EtcdTestServer) { ...@@ -55,7 +55,7 @@ func newStorage(t *testing.T) (ControllerStorage, *etcdtesting.EtcdTestServer) {
// createController is a helper function that returns a controller with the updated resource version. // createController is a helper function that returns a controller with the updated resource version.
func createController(storage *REST, rc api.ReplicationController, t *testing.T) (api.ReplicationController, error) { func createController(storage *REST, rc api.ReplicationController, t *testing.T) (api.ReplicationController, error) {
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), rc.Namespace) ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), rc.Namespace)
obj, err := storage.Create(ctx, &rc, false) obj, err := storage.Create(ctx, &rc, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Errorf("Failed to create controller, %v", err) t.Errorf("Failed to create controller, %v", err)
} }
...@@ -173,7 +173,7 @@ func TestGenerationNumber(t *testing.T) { ...@@ -173,7 +173,7 @@ func TestGenerationNumber(t *testing.T) {
// Updates to spec should increment the generation number // Updates to spec should increment the generation number
controller.Spec.Replicas += 1 controller.Spec.Replicas += 1
storage.Controller.Update(ctx, controller.Name, rest.DefaultUpdatedObjectInfo(controller)) storage.Controller.Update(ctx, controller.Name, rest.DefaultUpdatedObjectInfo(controller), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
...@@ -188,7 +188,7 @@ func TestGenerationNumber(t *testing.T) { ...@@ -188,7 +188,7 @@ func TestGenerationNumber(t *testing.T) {
// Updates to status should not increment either spec or status generation numbers // Updates to status should not increment either spec or status generation numbers
controller.Status.Replicas += 1 controller.Status.Replicas += 1
storage.Controller.Update(ctx, controller.Name, rest.DefaultUpdatedObjectInfo(controller)) storage.Controller.Update(ctx, controller.Name, rest.DefaultUpdatedObjectInfo(controller), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
...@@ -308,7 +308,7 @@ func TestScaleUpdate(t *testing.T) { ...@@ -308,7 +308,7 @@ func TestScaleUpdate(t *testing.T) {
}, },
} }
if _, _, err := storage.Scale.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update)); err != nil { if _, _, err := storage.Scale.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc); err != nil {
t.Fatalf("error updating scale %v: %v", update, err) t.Fatalf("error updating scale %v: %v", update, err)
} }
obj, err := storage.Scale.Get(ctx, name, &metav1.GetOptions{}) obj, err := storage.Scale.Get(ctx, name, &metav1.GetOptions{})
...@@ -323,7 +323,7 @@ func TestScaleUpdate(t *testing.T) { ...@@ -323,7 +323,7 @@ func TestScaleUpdate(t *testing.T) {
update.ResourceVersion = rc.ResourceVersion update.ResourceVersion = rc.ResourceVersion
update.Spec.Replicas = 15 update.Spec.Replicas = 15
if _, _, err = storage.Scale.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update)); err != nil && !errors.IsConflict(err) { if _, _, err = storage.Scale.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc); err != nil && !errors.IsConflict(err) {
t.Fatalf("unexpected error, expecting an update conflict but got %v", err) t.Fatalf("unexpected error, expecting an update conflict but got %v", err)
} }
} }
......
...@@ -77,6 +77,6 @@ func (r *StatusREST) Get(ctx genericapirequest.Context, name string, options *me ...@@ -77,6 +77,6 @@ func (r *StatusREST) Get(ctx genericapirequest.Context, name string, options *me
} }
// Update alters the status subset of an object. // Update alters the status subset of an object.
func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo) return r.store.Update(ctx, name, objInfo, createValidation, updateValidation)
} }
...@@ -87,7 +87,7 @@ func TestCreateSetsFields(t *testing.T) { ...@@ -87,7 +87,7 @@ func TestCreateSetsFields(t *testing.T) {
defer storage.Store.DestroyFunc() defer storage.Store.DestroyFunc()
ctx := genericapirequest.NewDefaultContext() ctx := genericapirequest.NewDefaultContext()
resourcequota := validNewResourceQuota() resourcequota := validNewResourceQuota()
_, err := storage.Create(genericapirequest.NewDefaultContext(), resourcequota, false) _, err := storage.Create(genericapirequest.NewDefaultContext(), resourcequota, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
...@@ -191,7 +191,7 @@ func TestUpdateStatus(t *testing.T) { ...@@ -191,7 +191,7 @@ func TestUpdateStatus(t *testing.T) {
}, },
} }
_, _, err = status.Update(ctx, resourcequotaIn.Name, rest.DefaultUpdatedObjectInfo(resourcequotaIn)) _, _, err = status.Update(ctx, resourcequotaIn.Name, rest.DefaultUpdatedObjectInfo(resourcequotaIn), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if err != nil { if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
......
...@@ -30,8 +30,8 @@ type Registry interface { ...@@ -30,8 +30,8 @@ type Registry interface {
ListSecrets(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*api.SecretList, error) ListSecrets(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*api.SecretList, error)
WatchSecrets(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error) WatchSecrets(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error)
GetSecret(ctx genericapirequest.Context, name string, options *metav1.GetOptions) (*api.Secret, error) GetSecret(ctx genericapirequest.Context, name string, options *metav1.GetOptions) (*api.Secret, error)
CreateSecret(ctx genericapirequest.Context, Secret *api.Secret) (*api.Secret, error) CreateSecret(ctx genericapirequest.Context, Secret *api.Secret, createValidation rest.ValidateObjectFunc) (*api.Secret, error)
UpdateSecret(ctx genericapirequest.Context, Secret *api.Secret) (*api.Secret, error) UpdateSecret(ctx genericapirequest.Context, Secret *api.Secret, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (*api.Secret, error)
DeleteSecret(ctx genericapirequest.Context, name string) error DeleteSecret(ctx genericapirequest.Context, name string) error
} }
...@@ -66,13 +66,13 @@ func (s *storage) GetSecret(ctx genericapirequest.Context, name string, options ...@@ -66,13 +66,13 @@ func (s *storage) GetSecret(ctx genericapirequest.Context, name string, options
return obj.(*api.Secret), nil return obj.(*api.Secret), nil
} }
func (s *storage) CreateSecret(ctx genericapirequest.Context, secret *api.Secret) (*api.Secret, error) { func (s *storage) CreateSecret(ctx genericapirequest.Context, secret *api.Secret, createValidation rest.ValidateObjectFunc) (*api.Secret, error) {
obj, err := s.Create(ctx, secret, false) obj, err := s.Create(ctx, secret, createValidation, false)
return obj.(*api.Secret), err return obj.(*api.Secret), err
} }
func (s *storage) UpdateSecret(ctx genericapirequest.Context, secret *api.Secret) (*api.Secret, error) { func (s *storage) UpdateSecret(ctx genericapirequest.Context, secret *api.Secret, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (*api.Secret, error) {
obj, _, err := s.Update(ctx, secret.Name, rest.DefaultUpdatedObjectInfo(secret)) obj, _, err := s.Update(ctx, secret.Name, rest.DefaultUpdatedObjectInfo(secret), createValidation, updateValidation)
return obj.(*api.Secret), err return obj.(*api.Secret), err
} }
......
...@@ -30,10 +30,10 @@ import ( ...@@ -30,10 +30,10 @@ import (
// Registry is an interface for things that know how to store services. // Registry is an interface for things that know how to store services.
type Registry interface { type Registry interface {
ListServices(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*api.ServiceList, error) ListServices(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*api.ServiceList, error)
CreateService(ctx genericapirequest.Context, svc *api.Service) (*api.Service, error) CreateService(ctx genericapirequest.Context, svc *api.Service, createValidation rest.ValidateObjectFunc) (*api.Service, error)
GetService(ctx genericapirequest.Context, name string, options *metav1.GetOptions) (*api.Service, error) GetService(ctx genericapirequest.Context, name string, options *metav1.GetOptions) (*api.Service, error)
DeleteService(ctx genericapirequest.Context, name string) error DeleteService(ctx genericapirequest.Context, name string) error
UpdateService(ctx genericapirequest.Context, svc *api.Service) (*api.Service, error) UpdateService(ctx genericapirequest.Context, svc *api.Service, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (*api.Service, error)
WatchServices(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error) WatchServices(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error)
ExportService(ctx genericapirequest.Context, name string, options metav1.ExportOptions) (*api.Service, error) ExportService(ctx genericapirequest.Context, name string, options metav1.ExportOptions) (*api.Service, error)
} }
...@@ -57,8 +57,8 @@ func (s *storage) ListServices(ctx genericapirequest.Context, options *metainter ...@@ -57,8 +57,8 @@ func (s *storage) ListServices(ctx genericapirequest.Context, options *metainter
return obj.(*api.ServiceList), nil return obj.(*api.ServiceList), nil
} }
func (s *storage) CreateService(ctx genericapirequest.Context, svc *api.Service) (*api.Service, error) { func (s *storage) CreateService(ctx genericapirequest.Context, svc *api.Service, createValidation rest.ValidateObjectFunc) (*api.Service, error) {
obj, err := s.Create(ctx, svc, false) obj, err := s.Create(ctx, svc, createValidation, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -78,8 +78,8 @@ func (s *storage) DeleteService(ctx genericapirequest.Context, name string) erro ...@@ -78,8 +78,8 @@ func (s *storage) DeleteService(ctx genericapirequest.Context, name string) erro
return err return err
} }
func (s *storage) UpdateService(ctx genericapirequest.Context, svc *api.Service) (*api.Service, error) { func (s *storage) UpdateService(ctx genericapirequest.Context, svc *api.Service, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (*api.Service, error) {
obj, _, err := s.Update(ctx, svc.Name, rest.DefaultUpdatedObjectInfo(svc)) obj, _, err := s.Update(ctx, svc.Name, rest.DefaultUpdatedObjectInfo(svc), createValidation, updateValidation)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -88,7 +88,7 @@ func (rs *REST) Categories() []string { ...@@ -88,7 +88,7 @@ func (rs *REST) Categories() []string {
} }
// TODO: implement includeUninitialized by refactoring this to move to store // TODO: implement includeUninitialized by refactoring this to move to store
func (rs *REST) Create(ctx genericapirequest.Context, obj runtime.Object, includeUninitialized bool) (runtime.Object, error) { func (rs *REST) Create(ctx genericapirequest.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, includeUninitialized bool) (runtime.Object, error) {
service := obj.(*api.Service) service := obj.(*api.Service)
if err := rest.BeforeCreate(Strategy, ctx, obj); err != nil { if err := rest.BeforeCreate(Strategy, ctx, obj); err != nil {
...@@ -133,7 +133,7 @@ func (rs *REST) Create(ctx genericapirequest.Context, obj runtime.Object, includ ...@@ -133,7 +133,7 @@ func (rs *REST) Create(ctx genericapirequest.Context, obj runtime.Object, includ
} }
} }
out, err := rs.registry.CreateService(ctx, service) out, err := rs.registry.CreateService(ctx, service, createValidation)
if err != nil { if err != nil {
err = rest.CheckGeneratedNameError(Strategy, err, service) err = rest.CheckGeneratedNameError(Strategy, err, service)
} }
...@@ -284,7 +284,7 @@ func (rs *REST) healthCheckNodePortUpdate(oldService, service *api.Service, node ...@@ -284,7 +284,7 @@ func (rs *REST) healthCheckNodePortUpdate(oldService, service *api.Service, node
return true, nil return true, nil
} }
func (rs *REST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { func (rs *REST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
oldService, err := rs.registry.GetService(ctx, name, &metav1.GetOptions{}) oldService, err := rs.registry.GetService(ctx, name, &metav1.GetOptions{})
if err != nil { if err != nil {
return nil, false, err return nil, false, err
...@@ -360,7 +360,7 @@ func (rs *REST) Update(ctx genericapirequest.Context, name string, objInfo rest. ...@@ -360,7 +360,7 @@ func (rs *REST) Update(ctx genericapirequest.Context, name string, objInfo rest.
} }
} }
out, err := rs.registry.UpdateService(ctx, service) out, err := rs.registry.UpdateService(ctx, service, createValidation, updateValidation)
if err == nil { if err == nil {
el := nodePortOp.Commit() el := nodePortOp.Commit()
if el != nil { if el != nil {
......
...@@ -111,7 +111,7 @@ func TestServiceRegistryCreate(t *testing.T) { ...@@ -111,7 +111,7 @@ func TestServiceRegistryCreate(t *testing.T) {
}, },
} }
ctx := genericapirequest.NewDefaultContext() ctx := genericapirequest.NewDefaultContext()
created_svc, err := storage.Create(ctx, svc, false) created_svc, err := storage.Create(ctx, svc, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
...@@ -235,7 +235,7 @@ func TestServiceRegistryCreateMultiNodePortsService(t *testing.T) { ...@@ -235,7 +235,7 @@ func TestServiceRegistryCreateMultiNodePortsService(t *testing.T) {
ctx := genericapirequest.NewDefaultContext() ctx := genericapirequest.NewDefaultContext()
for _, test := range testCases { for _, test := range testCases {
created_svc, err := storage.Create(ctx, test.svc, false) created_svc, err := storage.Create(ctx, test.svc, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
...@@ -311,7 +311,7 @@ func TestServiceStorageValidatesCreate(t *testing.T) { ...@@ -311,7 +311,7 @@ func TestServiceStorageValidatesCreate(t *testing.T) {
} }
ctx := genericapirequest.NewDefaultContext() ctx := genericapirequest.NewDefaultContext()
for _, failureCase := range failureCases { for _, failureCase := range failureCases {
c, err := storage.Create(ctx, &failureCase, false) c, err := storage.Create(ctx, &failureCase, rest.ValidateAllObjectFunc, false)
if c != nil { if c != nil {
t.Errorf("Expected nil object") t.Errorf("Expected nil object")
} }
...@@ -334,7 +334,7 @@ func TestServiceRegistryUpdate(t *testing.T) { ...@@ -334,7 +334,7 @@ func TestServiceRegistryUpdate(t *testing.T) {
TargetPort: intstr.FromInt(6502), TargetPort: intstr.FromInt(6502),
}}, }},
}, },
}) }, rest.ValidateAllObjectFunc)
if err != nil { if err != nil {
t.Fatalf("Expected no error: %v", err) t.Fatalf("Expected no error: %v", err)
...@@ -353,7 +353,7 @@ func TestServiceRegistryUpdate(t *testing.T) { ...@@ -353,7 +353,7 @@ func TestServiceRegistryUpdate(t *testing.T) {
TargetPort: intstr.FromInt(6502), TargetPort: intstr.FromInt(6502),
}}, }},
}, },
})) }), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if err != nil { if err != nil {
t.Fatalf("Expected no error: %v", err) t.Fatalf("Expected no error: %v", err)
} }
...@@ -384,7 +384,7 @@ func TestServiceStorageValidatesUpdate(t *testing.T) { ...@@ -384,7 +384,7 @@ func TestServiceStorageValidatesUpdate(t *testing.T) {
Protocol: api.ProtocolTCP, Protocol: api.ProtocolTCP,
}}, }},
}, },
}) }, rest.ValidateAllObjectFunc)
failureCases := map[string]api.Service{ failureCases := map[string]api.Service{
"empty ID": { "empty ID": {
ObjectMeta: metav1.ObjectMeta{Name: ""}, ObjectMeta: metav1.ObjectMeta{Name: ""},
...@@ -414,7 +414,7 @@ func TestServiceStorageValidatesUpdate(t *testing.T) { ...@@ -414,7 +414,7 @@ func TestServiceStorageValidatesUpdate(t *testing.T) {
}, },
} }
for _, failureCase := range failureCases { for _, failureCase := range failureCases {
c, created, err := storage.Update(ctx, failureCase.Name, rest.DefaultUpdatedObjectInfo(&failureCase)) c, created, err := storage.Update(ctx, failureCase.Name, rest.DefaultUpdatedObjectInfo(&failureCase), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if c != nil || created { if c != nil || created {
t.Errorf("Expected nil object or created false") t.Errorf("Expected nil object or created false")
} }
...@@ -440,7 +440,7 @@ func TestServiceRegistryExternalService(t *testing.T) { ...@@ -440,7 +440,7 @@ func TestServiceRegistryExternalService(t *testing.T) {
}}, }},
}, },
} }
_, err := storage.Create(ctx, svc, false) _, err := storage.Create(ctx, svc, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Errorf("Failed to create service: %#v", err) t.Errorf("Failed to create service: %#v", err)
} }
...@@ -477,7 +477,7 @@ func TestServiceRegistryDelete(t *testing.T) { ...@@ -477,7 +477,7 @@ func TestServiceRegistryDelete(t *testing.T) {
}}, }},
}, },
} }
registry.CreateService(ctx, svc) registry.CreateService(ctx, svc, rest.ValidateAllObjectFunc)
storage.Delete(ctx, svc.Name) storage.Delete(ctx, svc.Name)
if e, a := "foo", registry.DeletedID; e != a { if e, a := "foo", registry.DeletedID; e != a {
t.Errorf("Expected %v, but got %v", e, a) t.Errorf("Expected %v, but got %v", e, a)
...@@ -499,7 +499,7 @@ func TestServiceRegistryDeleteExternal(t *testing.T) { ...@@ -499,7 +499,7 @@ func TestServiceRegistryDeleteExternal(t *testing.T) {
}}, }},
}, },
} }
registry.CreateService(ctx, svc) registry.CreateService(ctx, svc, rest.ValidateAllObjectFunc)
storage.Delete(ctx, svc.Name) storage.Delete(ctx, svc.Name)
if e, a := "foo", registry.DeletedID; e != a { if e, a := "foo", registry.DeletedID; e != a {
t.Errorf("Expected %v, but got %v", e, a) t.Errorf("Expected %v, but got %v", e, a)
...@@ -524,14 +524,14 @@ func TestServiceRegistryUpdateExternalService(t *testing.T) { ...@@ -524,14 +524,14 @@ func TestServiceRegistryUpdateExternalService(t *testing.T) {
}}, }},
}, },
} }
if _, err := storage.Create(ctx, svc1, false); err != nil { if _, err := storage.Create(ctx, svc1, rest.ValidateAllObjectFunc, false); err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
// Modify load balancer to be external. // Modify load balancer to be external.
svc2 := svc1.DeepCopy() svc2 := svc1.DeepCopy()
svc2.Spec.Type = api.ServiceTypeLoadBalancer svc2.Spec.Type = api.ServiceTypeLoadBalancer
if _, _, err := storage.Update(ctx, svc2.Name, rest.DefaultUpdatedObjectInfo(svc2)); err != nil { if _, _, err := storage.Update(ctx, svc2.Name, rest.DefaultUpdatedObjectInfo(svc2), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc); err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
defer releaseServiceNodePorts(t, ctx, svc2.Name, storage, registry) defer releaseServiceNodePorts(t, ctx, svc2.Name, storage, registry)
...@@ -539,7 +539,7 @@ func TestServiceRegistryUpdateExternalService(t *testing.T) { ...@@ -539,7 +539,7 @@ func TestServiceRegistryUpdateExternalService(t *testing.T) {
// Change port. // Change port.
svc3 := svc2.DeepCopy() svc3 := svc2.DeepCopy()
svc3.Spec.Ports[0].Port = 6504 svc3.Spec.Ports[0].Port = 6504
if _, _, err := storage.Update(ctx, svc3.Name, rest.DefaultUpdatedObjectInfo(svc3)); err != nil { if _, _, err := storage.Update(ctx, svc3.Name, rest.DefaultUpdatedObjectInfo(svc3), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc); err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
} }
...@@ -568,7 +568,7 @@ func TestServiceRegistryUpdateMultiPortExternalService(t *testing.T) { ...@@ -568,7 +568,7 @@ func TestServiceRegistryUpdateMultiPortExternalService(t *testing.T) {
}}, }},
}, },
} }
if _, err := storage.Create(ctx, svc1, false); err != nil { if _, err := storage.Create(ctx, svc1, rest.ValidateAllObjectFunc, false); err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
defer releaseServiceNodePorts(t, ctx, svc1.Name, storage, registry) defer releaseServiceNodePorts(t, ctx, svc1.Name, storage, registry)
...@@ -576,7 +576,7 @@ func TestServiceRegistryUpdateMultiPortExternalService(t *testing.T) { ...@@ -576,7 +576,7 @@ func TestServiceRegistryUpdateMultiPortExternalService(t *testing.T) {
// Modify ports // Modify ports
svc2 := svc1.DeepCopy() svc2 := svc1.DeepCopy()
svc2.Spec.Ports[1].Port = 8088 svc2.Spec.Ports[1].Port = 8088
if _, _, err := storage.Update(ctx, svc2.Name, rest.DefaultUpdatedObjectInfo(svc2)); err != nil { if _, _, err := storage.Update(ctx, svc2.Name, rest.DefaultUpdatedObjectInfo(svc2), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc); err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
} }
...@@ -589,7 +589,7 @@ func TestServiceRegistryGet(t *testing.T) { ...@@ -589,7 +589,7 @@ func TestServiceRegistryGet(t *testing.T) {
Spec: api.ServiceSpec{ Spec: api.ServiceSpec{
Selector: map[string]string{"bar": "baz"}, Selector: map[string]string{"bar": "baz"},
}, },
}) }, rest.ValidateAllObjectFunc)
storage.Get(ctx, "foo", &metav1.GetOptions{}) storage.Get(ctx, "foo", &metav1.GetOptions{})
if e, a := "foo", registry.GottenID; e != a { if e, a := "foo", registry.GottenID; e != a {
t.Errorf("Expected %v, but got %v", e, a) t.Errorf("Expected %v, but got %v", e, a)
...@@ -642,7 +642,7 @@ func TestServiceRegistryResourceLocation(t *testing.T) { ...@@ -642,7 +642,7 @@ func TestServiceRegistryResourceLocation(t *testing.T) {
{Name: "", Port: 93, TargetPort: intstr.FromInt(80)}, {Name: "", Port: 93, TargetPort: intstr.FromInt(80)},
}, },
}, },
}) }, rest.ValidateAllObjectFunc)
redirector := rest.Redirector(storage) redirector := rest.Redirector(storage)
// Test a simple id. // Test a simple id.
...@@ -725,13 +725,13 @@ func TestServiceRegistryList(t *testing.T) { ...@@ -725,13 +725,13 @@ func TestServiceRegistryList(t *testing.T) {
Spec: api.ServiceSpec{ Spec: api.ServiceSpec{
Selector: map[string]string{"bar": "baz"}, Selector: map[string]string{"bar": "baz"},
}, },
}) }, rest.ValidateAllObjectFunc)
registry.CreateService(ctx, &api.Service{ registry.CreateService(ctx, &api.Service{
ObjectMeta: metav1.ObjectMeta{Name: "foo2", Namespace: metav1.NamespaceDefault}, ObjectMeta: metav1.ObjectMeta{Name: "foo2", Namespace: metav1.NamespaceDefault},
Spec: api.ServiceSpec{ Spec: api.ServiceSpec{
Selector: map[string]string{"bar2": "baz2"}, Selector: map[string]string{"bar2": "baz2"},
}, },
}) }, rest.ValidateAllObjectFunc)
registry.List.ResourceVersion = "1" registry.List.ResourceVersion = "1"
s, _ := storage.List(ctx, nil) s, _ := storage.List(ctx, nil)
sl := s.(*api.ServiceList) sl := s.(*api.ServiceList)
...@@ -766,7 +766,7 @@ func TestServiceRegistryIPAllocation(t *testing.T) { ...@@ -766,7 +766,7 @@ func TestServiceRegistryIPAllocation(t *testing.T) {
}, },
} }
ctx := genericapirequest.NewDefaultContext() ctx := genericapirequest.NewDefaultContext()
created_svc1, _ := storage.Create(ctx, svc1, false) created_svc1, _ := storage.Create(ctx, svc1, rest.ValidateAllObjectFunc, false)
created_service_1 := created_svc1.(*api.Service) created_service_1 := created_svc1.(*api.Service)
if created_service_1.Name != "foo" { if created_service_1.Name != "foo" {
t.Errorf("Expected foo, but got %v", created_service_1.Name) t.Errorf("Expected foo, but got %v", created_service_1.Name)
...@@ -788,7 +788,7 @@ func TestServiceRegistryIPAllocation(t *testing.T) { ...@@ -788,7 +788,7 @@ func TestServiceRegistryIPAllocation(t *testing.T) {
}}, }},
}} }}
ctx = genericapirequest.NewDefaultContext() ctx = genericapirequest.NewDefaultContext()
created_svc2, _ := storage.Create(ctx, svc2, false) created_svc2, _ := storage.Create(ctx, svc2, rest.ValidateAllObjectFunc, false)
created_service_2 := created_svc2.(*api.Service) created_service_2 := created_svc2.(*api.Service)
if created_service_2.Name != "bar" { if created_service_2.Name != "bar" {
t.Errorf("Expected bar, but got %v", created_service_2.Name) t.Errorf("Expected bar, but got %v", created_service_2.Name)
...@@ -821,7 +821,7 @@ func TestServiceRegistryIPAllocation(t *testing.T) { ...@@ -821,7 +821,7 @@ func TestServiceRegistryIPAllocation(t *testing.T) {
}, },
} }
ctx = genericapirequest.NewDefaultContext() ctx = genericapirequest.NewDefaultContext()
created_svc3, err := storage.Create(ctx, svc3, false) created_svc3, err := storage.Create(ctx, svc3, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -848,7 +848,7 @@ func TestServiceRegistryIPReallocation(t *testing.T) { ...@@ -848,7 +848,7 @@ func TestServiceRegistryIPReallocation(t *testing.T) {
}, },
} }
ctx := genericapirequest.NewDefaultContext() ctx := genericapirequest.NewDefaultContext()
created_svc1, _ := storage.Create(ctx, svc1, false) created_svc1, _ := storage.Create(ctx, svc1, rest.ValidateAllObjectFunc, false)
created_service_1 := created_svc1.(*api.Service) created_service_1 := created_svc1.(*api.Service)
if created_service_1.Name != "foo" { if created_service_1.Name != "foo" {
t.Errorf("Expected foo, but got %v", created_service_1.Name) t.Errorf("Expected foo, but got %v", created_service_1.Name)
...@@ -876,7 +876,7 @@ func TestServiceRegistryIPReallocation(t *testing.T) { ...@@ -876,7 +876,7 @@ func TestServiceRegistryIPReallocation(t *testing.T) {
}, },
} }
ctx = genericapirequest.NewDefaultContext() ctx = genericapirequest.NewDefaultContext()
created_svc2, _ := storage.Create(ctx, svc2, false) created_svc2, _ := storage.Create(ctx, svc2, rest.ValidateAllObjectFunc, false)
created_service_2 := created_svc2.(*api.Service) created_service_2 := created_svc2.(*api.Service)
if created_service_2.Name != "bar" { if created_service_2.Name != "bar" {
t.Errorf("Expected bar, but got %v", created_service_2.Name) t.Errorf("Expected bar, but got %v", created_service_2.Name)
...@@ -903,7 +903,7 @@ func TestServiceRegistryIPUpdate(t *testing.T) { ...@@ -903,7 +903,7 @@ func TestServiceRegistryIPUpdate(t *testing.T) {
}, },
} }
ctx := genericapirequest.NewDefaultContext() ctx := genericapirequest.NewDefaultContext()
created_svc, _ := storage.Create(ctx, svc, false) created_svc, _ := storage.Create(ctx, svc, rest.ValidateAllObjectFunc, false)
created_service := created_svc.(*api.Service) created_service := created_svc.(*api.Service)
if created_service.Spec.Ports[0].Port != 6502 { if created_service.Spec.Ports[0].Port != 6502 {
t.Errorf("Expected port 6502, but got %v", created_service.Spec.Ports[0].Port) t.Errorf("Expected port 6502, but got %v", created_service.Spec.Ports[0].Port)
...@@ -915,7 +915,7 @@ func TestServiceRegistryIPUpdate(t *testing.T) { ...@@ -915,7 +915,7 @@ func TestServiceRegistryIPUpdate(t *testing.T) {
update := created_service.DeepCopy() update := created_service.DeepCopy()
update.Spec.Ports[0].Port = 6503 update.Spec.Ports[0].Port = 6503
updated_svc, _, _ := storage.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(update)) updated_svc, _, _ := storage.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(update), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
updated_service := updated_svc.(*api.Service) updated_service := updated_svc.(*api.Service)
if updated_service.Spec.Ports[0].Port != 6503 { if updated_service.Spec.Ports[0].Port != 6503 {
t.Errorf("Expected port 6503, but got %v", updated_service.Spec.Ports[0].Port) t.Errorf("Expected port 6503, but got %v", updated_service.Spec.Ports[0].Port)
...@@ -934,7 +934,7 @@ func TestServiceRegistryIPUpdate(t *testing.T) { ...@@ -934,7 +934,7 @@ func TestServiceRegistryIPUpdate(t *testing.T) {
update.Spec.Ports[0].Port = 6503 update.Spec.Ports[0].Port = 6503
update.Spec.ClusterIP = testIP // Error: Cluster IP is immutable update.Spec.ClusterIP = testIP // Error: Cluster IP is immutable
_, _, err := storage.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(update)) _, _, err := storage.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(update), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if err == nil || !errors.IsInvalid(err) { if err == nil || !errors.IsInvalid(err) {
t.Errorf("Unexpected error type: %v", err) t.Errorf("Unexpected error type: %v", err)
} }
...@@ -957,7 +957,7 @@ func TestServiceRegistryIPLoadBalancer(t *testing.T) { ...@@ -957,7 +957,7 @@ func TestServiceRegistryIPLoadBalancer(t *testing.T) {
}, },
} }
ctx := genericapirequest.NewDefaultContext() ctx := genericapirequest.NewDefaultContext()
created_svc, err := storage.Create(ctx, svc, false) created_svc, err := storage.Create(ctx, svc, rest.ValidateAllObjectFunc, false)
if created_svc == nil || err != nil { if created_svc == nil || err != nil {
t.Errorf("Unexpected failure creating service %v", err) t.Errorf("Unexpected failure creating service %v", err)
} }
...@@ -973,7 +973,7 @@ func TestServiceRegistryIPLoadBalancer(t *testing.T) { ...@@ -973,7 +973,7 @@ func TestServiceRegistryIPLoadBalancer(t *testing.T) {
update := created_service.DeepCopy() update := created_service.DeepCopy()
_, _, err = storage.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(update)) _, _, err = storage.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(update), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if err != nil { if err != nil {
t.Errorf("Unexpected error %v", err) t.Errorf("Unexpected error %v", err)
} }
...@@ -986,7 +986,7 @@ func TestUpdateServiceWithConflictingNamespace(t *testing.T) { ...@@ -986,7 +986,7 @@ func TestUpdateServiceWithConflictingNamespace(t *testing.T) {
} }
ctx := genericapirequest.NewDefaultContext() ctx := genericapirequest.NewDefaultContext()
obj, created, err := storage.Update(ctx, service.Name, rest.DefaultUpdatedObjectInfo(service)) obj, created, err := storage.Update(ctx, service.Name, rest.DefaultUpdatedObjectInfo(service), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if obj != nil || created { if obj != nil || created {
t.Error("Expected a nil object, but we got a value or created was true") t.Error("Expected a nil object, but we got a value or created was true")
} }
...@@ -1016,7 +1016,7 @@ func TestServiceRegistryExternalTrafficHealthCheckNodePortAllocation(t *testing. ...@@ -1016,7 +1016,7 @@ func TestServiceRegistryExternalTrafficHealthCheckNodePortAllocation(t *testing.
ExternalTrafficPolicy: api.ServiceExternalTrafficPolicyTypeLocal, ExternalTrafficPolicy: api.ServiceExternalTrafficPolicyTypeLocal,
}, },
} }
created_svc, err := storage.Create(ctx, svc, false) created_svc, err := storage.Create(ctx, svc, rest.ValidateAllObjectFunc, false)
if created_svc == nil || err != nil { if created_svc == nil || err != nil {
t.Errorf("Unexpected failure creating service %v", err) t.Errorf("Unexpected failure creating service %v", err)
} }
...@@ -1056,7 +1056,7 @@ func TestServiceRegistryExternalTrafficHealthCheckNodePortUserAllocation(t *test ...@@ -1056,7 +1056,7 @@ func TestServiceRegistryExternalTrafficHealthCheckNodePortUserAllocation(t *test
HealthCheckNodePort: randomNodePort, HealthCheckNodePort: randomNodePort,
}, },
} }
created_svc, err := storage.Create(ctx, svc, false) created_svc, err := storage.Create(ctx, svc, rest.ValidateAllObjectFunc, false)
if created_svc == nil || err != nil { if created_svc == nil || err != nil {
t.Fatalf("Unexpected failure creating service :%v", err) t.Fatalf("Unexpected failure creating service :%v", err)
} }
...@@ -1098,7 +1098,7 @@ func TestServiceRegistryExternalTrafficHealthCheckNodePortNegative(t *testing.T) ...@@ -1098,7 +1098,7 @@ func TestServiceRegistryExternalTrafficHealthCheckNodePortNegative(t *testing.T)
HealthCheckNodePort: int32(-1), HealthCheckNodePort: int32(-1),
}, },
} }
created_svc, err := storage.Create(ctx, svc, false) created_svc, err := storage.Create(ctx, svc, rest.ValidateAllObjectFunc, false)
if created_svc == nil || err != nil { if created_svc == nil || err != nil {
return return
} }
...@@ -1123,7 +1123,7 @@ func TestServiceRegistryExternalTrafficGlobal(t *testing.T) { ...@@ -1123,7 +1123,7 @@ func TestServiceRegistryExternalTrafficGlobal(t *testing.T) {
ExternalTrafficPolicy: api.ServiceExternalTrafficPolicyTypeCluster, ExternalTrafficPolicy: api.ServiceExternalTrafficPolicyTypeCluster,
}, },
} }
created_svc, err := storage.Create(ctx, svc, false) created_svc, err := storage.Create(ctx, svc, rest.ValidateAllObjectFunc, false)
if created_svc == nil || err != nil { if created_svc == nil || err != nil {
t.Errorf("Unexpected failure creating service %v", err) t.Errorf("Unexpected failure creating service %v", err)
} }
......
...@@ -89,6 +89,6 @@ func (r *StatusREST) Get(ctx genericapirequest.Context, name string, options *me ...@@ -89,6 +89,6 @@ func (r *StatusREST) Get(ctx genericapirequest.Context, name string, options *me
} }
// Update alters the status subset of an object. // Update alters the status subset of an object.
func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo) return r.store.Update(ctx, name, objInfo, createValidation, updateValidation)
} }
...@@ -30,8 +30,8 @@ type Registry interface { ...@@ -30,8 +30,8 @@ type Registry interface {
ListServiceAccounts(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*api.ServiceAccountList, error) ListServiceAccounts(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*api.ServiceAccountList, error)
WatchServiceAccounts(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error) WatchServiceAccounts(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error)
GetServiceAccount(ctx genericapirequest.Context, name string, options *metav1.GetOptions) (*api.ServiceAccount, error) GetServiceAccount(ctx genericapirequest.Context, name string, options *metav1.GetOptions) (*api.ServiceAccount, error)
CreateServiceAccount(ctx genericapirequest.Context, ServiceAccount *api.ServiceAccount) error CreateServiceAccount(ctx genericapirequest.Context, ServiceAccount *api.ServiceAccount, createValidation rest.ValidateObjectFunc) error
UpdateServiceAccount(ctx genericapirequest.Context, ServiceAccount *api.ServiceAccount) error UpdateServiceAccount(ctx genericapirequest.Context, ServiceAccount *api.ServiceAccount, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) error
DeleteServiceAccount(ctx genericapirequest.Context, name string) error DeleteServiceAccount(ctx genericapirequest.Context, name string) error
} }
...@@ -66,13 +66,13 @@ func (s *storage) GetServiceAccount(ctx genericapirequest.Context, name string, ...@@ -66,13 +66,13 @@ func (s *storage) GetServiceAccount(ctx genericapirequest.Context, name string,
return obj.(*api.ServiceAccount), nil return obj.(*api.ServiceAccount), nil
} }
func (s *storage) CreateServiceAccount(ctx genericapirequest.Context, serviceAccount *api.ServiceAccount) error { func (s *storage) CreateServiceAccount(ctx genericapirequest.Context, serviceAccount *api.ServiceAccount, createValidation rest.ValidateObjectFunc) error {
_, err := s.Create(ctx, serviceAccount, false) _, err := s.Create(ctx, serviceAccount, createValidation, false)
return err return err
} }
func (s *storage) UpdateServiceAccount(ctx genericapirequest.Context, serviceAccount *api.ServiceAccount) error { func (s *storage) UpdateServiceAccount(ctx genericapirequest.Context, serviceAccount *api.ServiceAccount, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) error {
_, _, err := s.Update(ctx, serviceAccount.Name, rest.DefaultUpdatedObjectInfo(serviceAccount)) _, _, err := s.Update(ctx, serviceAccount.Name, rest.DefaultUpdatedObjectInfo(serviceAccount), createValidation, updateValidation)
return err return err
} }
......
...@@ -69,7 +69,7 @@ func (r *ScaleREST) Get(ctx genericapirequest.Context, name string, options *met ...@@ -69,7 +69,7 @@ func (r *ScaleREST) Get(ctx genericapirequest.Context, name string, options *met
return scaleFromRC(rc), nil return scaleFromRC(rc), nil
} }
func (r *ScaleREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { func (r *ScaleREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
rc, err := (*r.registry).GetController(ctx, name, &metav1.GetOptions{}) rc, err := (*r.registry).GetController(ctx, name, &metav1.GetOptions{})
if err != nil { if err != nil {
return nil, false, errors.NewNotFound(extensions.Resource("replicationcontrollers/scale"), name) return nil, false, errors.NewNotFound(extensions.Resource("replicationcontrollers/scale"), name)
...@@ -92,7 +92,7 @@ func (r *ScaleREST) Update(ctx genericapirequest.Context, name string, objInfo r ...@@ -92,7 +92,7 @@ func (r *ScaleREST) Update(ctx genericapirequest.Context, name string, objInfo r
rc.Spec.Replicas = scale.Spec.Replicas rc.Spec.Replicas = scale.Spec.Replicas
rc.ResourceVersion = scale.ResourceVersion rc.ResourceVersion = scale.ResourceVersion
rc, err = (*r.registry).UpdateController(ctx, rc) rc, err = (*r.registry).UpdateController(ctx, rc, createValidation, updateValidation)
if err != nil { if err != nil {
return nil, false, errors.NewConflict(extensions.Resource("replicationcontrollers/scale"), scale.Name, err) return nil, false, errors.NewConflict(extensions.Resource("replicationcontrollers/scale"), scale.Name, err)
} }
......
...@@ -123,7 +123,7 @@ func TestUpdate(t *testing.T) { ...@@ -123,7 +123,7 @@ func TestUpdate(t *testing.T) {
}, },
} }
if _, _, err := storage.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update)); err != nil { if _, _, err := storage.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc); err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
obj, err := storage.Get(ctx, "foo", &metav1.GetOptions{}) obj, err := storage.Get(ctx, "foo", &metav1.GetOptions{})
......
...@@ -89,6 +89,6 @@ func (r *StatusREST) Get(ctx genericapirequest.Context, name string, options *me ...@@ -89,6 +89,6 @@ func (r *StatusREST) Get(ctx genericapirequest.Context, name string, options *me
} }
// Update alters the status subset of an object. // Update alters the status subset of an object.
func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo) return r.store.Update(ctx, name, objInfo, createValidation, updateValidation)
} }
...@@ -30,8 +30,8 @@ import ( ...@@ -30,8 +30,8 @@ import (
type Registry interface { type Registry interface {
ListDeployments(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*extensions.DeploymentList, error) ListDeployments(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*extensions.DeploymentList, error)
GetDeployment(ctx genericapirequest.Context, deploymentID string, options *metav1.GetOptions) (*extensions.Deployment, error) GetDeployment(ctx genericapirequest.Context, deploymentID string, options *metav1.GetOptions) (*extensions.Deployment, error)
CreateDeployment(ctx genericapirequest.Context, deployment *extensions.Deployment) (*extensions.Deployment, error) CreateDeployment(ctx genericapirequest.Context, deployment *extensions.Deployment, createValidation rest.ValidateObjectFunc) (*extensions.Deployment, error)
UpdateDeployment(ctx genericapirequest.Context, deployment *extensions.Deployment) (*extensions.Deployment, error) UpdateDeployment(ctx genericapirequest.Context, deployment *extensions.Deployment, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (*extensions.Deployment, error)
DeleteDeployment(ctx genericapirequest.Context, deploymentID string) error DeleteDeployment(ctx genericapirequest.Context, deploymentID string) error
} }
...@@ -64,16 +64,16 @@ func (s *storage) GetDeployment(ctx genericapirequest.Context, deploymentID stri ...@@ -64,16 +64,16 @@ func (s *storage) GetDeployment(ctx genericapirequest.Context, deploymentID stri
return obj.(*extensions.Deployment), nil return obj.(*extensions.Deployment), nil
} }
func (s *storage) CreateDeployment(ctx genericapirequest.Context, deployment *extensions.Deployment) (*extensions.Deployment, error) { func (s *storage) CreateDeployment(ctx genericapirequest.Context, deployment *extensions.Deployment, createValidation rest.ValidateObjectFunc) (*extensions.Deployment, error) {
obj, err := s.Create(ctx, deployment, false) obj, err := s.Create(ctx, deployment, createValidation, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return obj.(*extensions.Deployment), nil return obj.(*extensions.Deployment), nil
} }
func (s *storage) UpdateDeployment(ctx genericapirequest.Context, deployment *extensions.Deployment) (*extensions.Deployment, error) { func (s *storage) UpdateDeployment(ctx genericapirequest.Context, deployment *extensions.Deployment, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (*extensions.Deployment, error) {
obj, _, err := s.Update(ctx, deployment.Name, rest.DefaultUpdatedObjectInfo(deployment)) obj, _, err := s.Update(ctx, deployment.Name, rest.DefaultUpdatedObjectInfo(deployment), createValidation, updateValidation)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -115,8 +115,8 @@ func (r *StatusREST) Get(ctx genericapirequest.Context, name string, options *me ...@@ -115,8 +115,8 @@ func (r *StatusREST) Get(ctx genericapirequest.Context, name string, options *me
} }
// Update alters the status subset of an object. // Update alters the status subset of an object.
func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo) return r.store.Update(ctx, name, objInfo, createValidation, updateValidation)
} }
// RollbackREST implements the REST endpoint for initiating the rollback of a deployment // RollbackREST implements the REST endpoint for initiating the rollback of a deployment
...@@ -131,7 +131,7 @@ func (r *RollbackREST) New() runtime.Object { ...@@ -131,7 +131,7 @@ func (r *RollbackREST) New() runtime.Object {
var _ = rest.Creater(&RollbackREST{}) var _ = rest.Creater(&RollbackREST{})
func (r *RollbackREST) Create(ctx genericapirequest.Context, obj runtime.Object, includeUninitialized bool) (runtime.Object, error) { func (r *RollbackREST) Create(ctx genericapirequest.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, includeUninitialized bool) (runtime.Object, error) {
rollback, ok := obj.(*extensions.DeploymentRollback) rollback, ok := obj.(*extensions.DeploymentRollback)
if !ok { if !ok {
return nil, errors.NewBadRequest(fmt.Sprintf("not a DeploymentRollback: %#v", obj)) return nil, errors.NewBadRequest(fmt.Sprintf("not a DeploymentRollback: %#v", obj))
...@@ -227,7 +227,7 @@ func (r *ScaleREST) Get(ctx genericapirequest.Context, name string, options *met ...@@ -227,7 +227,7 @@ func (r *ScaleREST) Get(ctx genericapirequest.Context, name string, options *met
return scale, nil return scale, nil
} }
func (r *ScaleREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { func (r *ScaleREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
deployment, err := r.registry.GetDeployment(ctx, name, &metav1.GetOptions{}) deployment, err := r.registry.GetDeployment(ctx, name, &metav1.GetOptions{})
if err != nil { if err != nil {
return nil, false, errors.NewNotFound(extensions.Resource("deployments/scale"), name) return nil, false, errors.NewNotFound(extensions.Resource("deployments/scale"), name)
...@@ -256,7 +256,7 @@ func (r *ScaleREST) Update(ctx genericapirequest.Context, name string, objInfo r ...@@ -256,7 +256,7 @@ func (r *ScaleREST) Update(ctx genericapirequest.Context, name string, objInfo r
deployment.Spec.Replicas = scale.Spec.Replicas deployment.Spec.Replicas = scale.Spec.Replicas
deployment.ResourceVersion = scale.ResourceVersion deployment.ResourceVersion = scale.ResourceVersion
deployment, err = r.registry.UpdateDeployment(ctx, deployment) deployment, err = r.registry.UpdateDeployment(ctx, deployment, createValidation, updateValidation)
if err != nil { if err != nil {
return nil, false, err return nil, false, err
} }
......
...@@ -251,7 +251,7 @@ func TestScaleUpdate(t *testing.T) { ...@@ -251,7 +251,7 @@ func TestScaleUpdate(t *testing.T) {
}, },
} }
if _, _, err := storage.Scale.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update)); err != nil { if _, _, err := storage.Scale.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc); err != nil {
t.Fatalf("error updating scale %v: %v", update, err) t.Fatalf("error updating scale %v: %v", update, err)
} }
obj, err := storage.Scale.Get(ctx, name, &metav1.GetOptions{}) obj, err := storage.Scale.Get(ctx, name, &metav1.GetOptions{})
...@@ -266,7 +266,7 @@ func TestScaleUpdate(t *testing.T) { ...@@ -266,7 +266,7 @@ func TestScaleUpdate(t *testing.T) {
update.ResourceVersion = deployment.ResourceVersion update.ResourceVersion = deployment.ResourceVersion
update.Spec.Replicas = 15 update.Spec.Replicas = 15
if _, _, err = storage.Scale.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update)); err != nil && !errors.IsConflict(err) { if _, _, err = storage.Scale.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc); err != nil && !errors.IsConflict(err) {
t.Fatalf("unexpected error, expecting an update conflict but got %v", err) t.Fatalf("unexpected error, expecting an update conflict but got %v", err)
} }
} }
...@@ -290,7 +290,7 @@ func TestStatusUpdate(t *testing.T) { ...@@ -290,7 +290,7 @@ func TestStatusUpdate(t *testing.T) {
}, },
} }
if _, _, err := storage.Status.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update)); err != nil { if _, _, err := storage.Status.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc); err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
obj, err := storage.Deployment.Get(ctx, name, &metav1.GetOptions{}) obj, err := storage.Deployment.Get(ctx, name, &metav1.GetOptions{})
...@@ -341,10 +341,10 @@ func TestEtcdCreateDeploymentRollback(t *testing.T) { ...@@ -341,10 +341,10 @@ func TestEtcdCreateDeploymentRollback(t *testing.T) {
storage, server := newStorage(t) storage, server := newStorage(t)
rollbackStorage := storage.Rollback rollbackStorage := storage.Rollback
if _, err := storage.Deployment.Create(ctx, validNewDeployment(), false); err != nil { if _, err := storage.Deployment.Create(ctx, validNewDeployment(), rest.ValidateAllObjectFunc, false); err != nil {
t.Fatalf("%s: unexpected error: %v", k, err) t.Fatalf("%s: unexpected error: %v", k, err)
} }
rollbackRespStatus, err := rollbackStorage.Create(ctx, &test.rollback, false) rollbackRespStatus, err := rollbackStorage.Create(ctx, &test.rollback, rest.ValidateAllObjectFunc, false)
if !test.errOK(err) { if !test.errOK(err) {
t.Errorf("%s: unexpected error: %v", k, err) t.Errorf("%s: unexpected error: %v", k, err)
} else if err == nil { } else if err == nil {
...@@ -381,7 +381,7 @@ func TestEtcdCreateDeploymentRollbackNoDeployment(t *testing.T) { ...@@ -381,7 +381,7 @@ func TestEtcdCreateDeploymentRollbackNoDeployment(t *testing.T) {
Name: name, Name: name,
UpdatedAnnotations: map[string]string{}, UpdatedAnnotations: map[string]string{},
RollbackTo: extensions.RollbackConfig{Revision: 1}, RollbackTo: extensions.RollbackConfig{Revision: 1},
}, false) }, rest.ValidateAllObjectFunc, false)
if err == nil { if err == nil {
t.Fatalf("Expected not-found-error but got nothing") t.Fatalf("Expected not-found-error but got nothing")
} }
......
...@@ -81,6 +81,6 @@ func (r *StatusREST) Get(ctx genericapirequest.Context, name string, options *me ...@@ -81,6 +81,6 @@ func (r *StatusREST) Get(ctx genericapirequest.Context, name string, options *me
} }
// Update alters the status subset of an object. // Update alters the status subset of an object.
func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo) return r.store.Update(ctx, name, objInfo, createValidation, updateValidation)
} }
...@@ -34,8 +34,8 @@ type Registry interface { ...@@ -34,8 +34,8 @@ type Registry interface {
ListReplicaSets(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*extensions.ReplicaSetList, error) ListReplicaSets(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*extensions.ReplicaSetList, error)
WatchReplicaSets(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error) WatchReplicaSets(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error)
GetReplicaSet(ctx genericapirequest.Context, replicaSetID string, options *metav1.GetOptions) (*extensions.ReplicaSet, error) GetReplicaSet(ctx genericapirequest.Context, replicaSetID string, options *metav1.GetOptions) (*extensions.ReplicaSet, error)
CreateReplicaSet(ctx genericapirequest.Context, replicaSet *extensions.ReplicaSet) (*extensions.ReplicaSet, error) CreateReplicaSet(ctx genericapirequest.Context, replicaSet *extensions.ReplicaSet, createValidation rest.ValidateObjectFunc) (*extensions.ReplicaSet, error)
UpdateReplicaSet(ctx genericapirequest.Context, replicaSet *extensions.ReplicaSet) (*extensions.ReplicaSet, error) UpdateReplicaSet(ctx genericapirequest.Context, replicaSet *extensions.ReplicaSet, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (*extensions.ReplicaSet, error)
DeleteReplicaSet(ctx genericapirequest.Context, replicaSetID string) error DeleteReplicaSet(ctx genericapirequest.Context, replicaSetID string) error
} }
...@@ -73,16 +73,16 @@ func (s *storage) GetReplicaSet(ctx genericapirequest.Context, replicaSetID stri ...@@ -73,16 +73,16 @@ func (s *storage) GetReplicaSet(ctx genericapirequest.Context, replicaSetID stri
return obj.(*extensions.ReplicaSet), nil return obj.(*extensions.ReplicaSet), nil
} }
func (s *storage) CreateReplicaSet(ctx genericapirequest.Context, replicaSet *extensions.ReplicaSet) (*extensions.ReplicaSet, error) { func (s *storage) CreateReplicaSet(ctx genericapirequest.Context, replicaSet *extensions.ReplicaSet, createValidation rest.ValidateObjectFunc) (*extensions.ReplicaSet, error) {
obj, err := s.Create(ctx, replicaSet, false) obj, err := s.Create(ctx, replicaSet, createValidation, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return obj.(*extensions.ReplicaSet), nil return obj.(*extensions.ReplicaSet), nil
} }
func (s *storage) UpdateReplicaSet(ctx genericapirequest.Context, replicaSet *extensions.ReplicaSet) (*extensions.ReplicaSet, error) { func (s *storage) UpdateReplicaSet(ctx genericapirequest.Context, replicaSet *extensions.ReplicaSet, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (*extensions.ReplicaSet, error) {
obj, _, err := s.Update(ctx, replicaSet.Name, rest.DefaultUpdatedObjectInfo(replicaSet)) obj, _, err := s.Update(ctx, replicaSet.Name, rest.DefaultUpdatedObjectInfo(replicaSet), createValidation, updateValidation)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -119,8 +119,8 @@ func (r *StatusREST) Get(ctx genericapirequest.Context, name string, options *me ...@@ -119,8 +119,8 @@ func (r *StatusREST) Get(ctx genericapirequest.Context, name string, options *me
} }
// Update alters the status subset of an object. // Update alters the status subset of an object.
func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo) return r.store.Update(ctx, name, objInfo, createValidation, updateValidation)
} }
type ScaleREST struct { type ScaleREST struct {
...@@ -161,7 +161,7 @@ func (r *ScaleREST) Get(ctx genericapirequest.Context, name string, options *met ...@@ -161,7 +161,7 @@ func (r *ScaleREST) Get(ctx genericapirequest.Context, name string, options *met
return scale, err return scale, err
} }
func (r *ScaleREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { func (r *ScaleREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
rs, err := r.registry.GetReplicaSet(ctx, name, &metav1.GetOptions{}) rs, err := r.registry.GetReplicaSet(ctx, name, &metav1.GetOptions{})
if err != nil { if err != nil {
return nil, false, errors.NewNotFound(extensions.Resource("replicasets/scale"), name) return nil, false, errors.NewNotFound(extensions.Resource("replicasets/scale"), name)
...@@ -172,6 +172,7 @@ func (r *ScaleREST) Update(ctx genericapirequest.Context, name string, objInfo r ...@@ -172,6 +172,7 @@ func (r *ScaleREST) Update(ctx genericapirequest.Context, name string, objInfo r
return nil, false, err return nil, false, err
} }
// TODO: should this pass admission?
obj, err := objInfo.UpdatedObject(ctx, oldScale) obj, err := objInfo.UpdatedObject(ctx, oldScale)
if err != nil { if err != nil {
return nil, false, err return nil, false, err
...@@ -190,7 +191,7 @@ func (r *ScaleREST) Update(ctx genericapirequest.Context, name string, objInfo r ...@@ -190,7 +191,7 @@ func (r *ScaleREST) Update(ctx genericapirequest.Context, name string, objInfo r
rs.Spec.Replicas = scale.Spec.Replicas rs.Spec.Replicas = scale.Spec.Replicas
rs.ResourceVersion = scale.ResourceVersion rs.ResourceVersion = scale.ResourceVersion
rs, err = r.registry.UpdateReplicaSet(ctx, rs) rs, err = r.registry.UpdateReplicaSet(ctx, rs, createValidation, updateValidation)
if err != nil { if err != nil {
return nil, false, err return nil, false, err
} }
......
...@@ -47,7 +47,7 @@ func newStorage(t *testing.T) (*ReplicaSetStorage, *etcdtesting.EtcdTestServer) ...@@ -47,7 +47,7 @@ func newStorage(t *testing.T) (*ReplicaSetStorage, *etcdtesting.EtcdTestServer)
// createReplicaSet is a helper function that returns a ReplicaSet with the updated resource version. // createReplicaSet is a helper function that returns a ReplicaSet with the updated resource version.
func createReplicaSet(storage *REST, rs extensions.ReplicaSet, t *testing.T) (extensions.ReplicaSet, error) { func createReplicaSet(storage *REST, rs extensions.ReplicaSet, t *testing.T) (extensions.ReplicaSet, error) {
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), rs.Namespace) ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), rs.Namespace)
obj, err := storage.Create(ctx, &rs, false) obj, err := storage.Create(ctx, &rs, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Errorf("Failed to create ReplicaSet, %v", err) t.Errorf("Failed to create ReplicaSet, %v", err)
} }
...@@ -169,7 +169,7 @@ func TestGenerationNumber(t *testing.T) { ...@@ -169,7 +169,7 @@ func TestGenerationNumber(t *testing.T) {
// Updates to spec should increment the generation number // Updates to spec should increment the generation number
storedRS.Spec.Replicas += 1 storedRS.Spec.Replicas += 1
storage.ReplicaSet.Update(ctx, storedRS.Name, rest.DefaultUpdatedObjectInfo(storedRS)) storage.ReplicaSet.Update(ctx, storedRS.Name, rest.DefaultUpdatedObjectInfo(storedRS), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
...@@ -184,7 +184,7 @@ func TestGenerationNumber(t *testing.T) { ...@@ -184,7 +184,7 @@ func TestGenerationNumber(t *testing.T) {
// Updates to status should not increment either spec or status generation numbers // Updates to status should not increment either spec or status generation numbers
storedRS.Status.Replicas += 1 storedRS.Status.Replicas += 1
storage.ReplicaSet.Update(ctx, storedRS.Name, rest.DefaultUpdatedObjectInfo(storedRS)) storage.ReplicaSet.Update(ctx, storedRS.Name, rest.DefaultUpdatedObjectInfo(storedRS), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
...@@ -311,7 +311,7 @@ func TestScaleUpdate(t *testing.T) { ...@@ -311,7 +311,7 @@ func TestScaleUpdate(t *testing.T) {
}, },
} }
if _, _, err := storage.Scale.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update)); err != nil { if _, _, err := storage.Scale.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc); err != nil {
t.Fatalf("error updating scale %v: %v", update, err) t.Fatalf("error updating scale %v: %v", update, err)
} }
...@@ -327,7 +327,7 @@ func TestScaleUpdate(t *testing.T) { ...@@ -327,7 +327,7 @@ func TestScaleUpdate(t *testing.T) {
update.ResourceVersion = rs.ResourceVersion update.ResourceVersion = rs.ResourceVersion
update.Spec.Replicas = 15 update.Spec.Replicas = 15
if _, _, err = storage.Scale.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update)); err != nil && !errors.IsConflict(err) { if _, _, err = storage.Scale.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc); err != nil && !errors.IsConflict(err) {
t.Fatalf("unexpected error, expecting an update conflict but got %v", err) t.Fatalf("unexpected error, expecting an update conflict but got %v", err)
} }
} }
...@@ -352,7 +352,7 @@ func TestStatusUpdate(t *testing.T) { ...@@ -352,7 +352,7 @@ func TestStatusUpdate(t *testing.T) {
}, },
} }
if _, _, err := storage.Status.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update)); err != nil { if _, _, err := storage.Status.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc); err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
obj, err := storage.ReplicaSet.Get(ctx, "foo", &metav1.GetOptions{}) obj, err := storage.ReplicaSet.Get(ctx, "foo", &metav1.GetOptions{})
......
...@@ -28,8 +28,8 @@ import ( ...@@ -28,8 +28,8 @@ import (
// Registry is an interface for things that know how to store NetworkPolicies. // Registry is an interface for things that know how to store NetworkPolicies.
type Registry interface { type Registry interface {
ListNetworkPolicies(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*networking.NetworkPolicyList, error) ListNetworkPolicies(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*networking.NetworkPolicyList, error)
CreateNetworkPolicy(ctx genericapirequest.Context, np *networking.NetworkPolicy) error CreateNetworkPolicy(ctx genericapirequest.Context, np *networking.NetworkPolicy, createValidation rest.ValidateObjectFunc) error
UpdateNetworkPolicy(ctx genericapirequest.Context, np *networking.NetworkPolicy) error UpdateNetworkPolicy(ctx genericapirequest.Context, np *networking.NetworkPolicy, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) error
GetNetworkPolicy(ctx genericapirequest.Context, name string, options *metav1.GetOptions) (*networking.NetworkPolicy, error) GetNetworkPolicy(ctx genericapirequest.Context, name string, options *metav1.GetOptions) (*networking.NetworkPolicy, error)
DeleteNetworkPolicy(ctx genericapirequest.Context, name string) error DeleteNetworkPolicy(ctx genericapirequest.Context, name string) error
WatchNetworkPolicies(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error) WatchNetworkPolicies(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error)
...@@ -55,13 +55,13 @@ func (s *storage) ListNetworkPolicies(ctx genericapirequest.Context, options *me ...@@ -55,13 +55,13 @@ func (s *storage) ListNetworkPolicies(ctx genericapirequest.Context, options *me
return obj.(*networking.NetworkPolicyList), nil return obj.(*networking.NetworkPolicyList), nil
} }
func (s *storage) CreateNetworkPolicy(ctx genericapirequest.Context, np *networking.NetworkPolicy) error { func (s *storage) CreateNetworkPolicy(ctx genericapirequest.Context, np *networking.NetworkPolicy, createValidation rest.ValidateObjectFunc) error {
_, err := s.Create(ctx, np, false) _, err := s.Create(ctx, np, createValidation, false)
return err return err
} }
func (s *storage) UpdateNetworkPolicy(ctx genericapirequest.Context, np *networking.NetworkPolicy) error { func (s *storage) UpdateNetworkPolicy(ctx genericapirequest.Context, np *networking.NetworkPolicy, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) error {
_, _, err := s.Update(ctx, np.Name, rest.DefaultUpdatedObjectInfo(np)) _, _, err := s.Update(ctx, np.Name, rest.DefaultUpdatedObjectInfo(np), createValidation, updateValidation)
return err return err
} }
......
...@@ -78,6 +78,6 @@ func (r *StatusREST) Get(ctx genericapirequest.Context, name string, options *me ...@@ -78,6 +78,6 @@ func (r *StatusREST) Get(ctx genericapirequest.Context, name string, options *me
} }
// Update alters the status subset of an object. // Update alters the status subset of an object.
func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo) return r.store.Update(ctx, name, objInfo, createValidation, updateValidation)
} }
...@@ -41,7 +41,7 @@ func newStorage(t *testing.T) (*REST, *StatusREST, *etcdtesting.EtcdTestServer) ...@@ -41,7 +41,7 @@ func newStorage(t *testing.T) (*REST, *StatusREST, *etcdtesting.EtcdTestServer)
// createPodDisruptionBudget is a helper function that returns a PodDisruptionBudget with the updated resource version. // createPodDisruptionBudget is a helper function that returns a PodDisruptionBudget with the updated resource version.
func createPodDisruptionBudget(storage *REST, pdb policy.PodDisruptionBudget, t *testing.T) (policy.PodDisruptionBudget, error) { func createPodDisruptionBudget(storage *REST, pdb policy.PodDisruptionBudget, t *testing.T) (policy.PodDisruptionBudget, error) {
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), pdb.Namespace) ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), pdb.Namespace)
obj, err := storage.Create(ctx, &pdb, false) obj, err := storage.Create(ctx, &pdb, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Errorf("Failed to create PodDisruptionBudget, %v", err) t.Errorf("Failed to create PodDisruptionBudget, %v", err)
} }
...@@ -109,7 +109,7 @@ func TestStatusUpdate(t *testing.T) { ...@@ -109,7 +109,7 @@ func TestStatusUpdate(t *testing.T) {
}, },
} }
if _, _, err := statusStorage.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update)); err != nil { if _, _, err := statusStorage.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc); err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
obj, err = storage.Get(ctx, "foo", &metav1.GetOptions{}) obj, err = storage.Get(ctx, "foo", &metav1.GetOptions{})
......
...@@ -40,9 +40,9 @@ func NewStorage(s rest.StandardStorage, ruleResolver rbacregistryvalidation.Auth ...@@ -40,9 +40,9 @@ func NewStorage(s rest.StandardStorage, ruleResolver rbacregistryvalidation.Auth
return &Storage{s, ruleResolver} return &Storage{s, ruleResolver}
} }
func (s *Storage) Create(ctx genericapirequest.Context, obj runtime.Object, includeUninitialized bool) (runtime.Object, error) { func (s *Storage) Create(ctx genericapirequest.Context, obj runtime.Object, createValidatingAdmission rest.ValidateObjectFunc, includeUninitialized bool) (runtime.Object, error) {
if rbacregistry.EscalationAllowed(ctx) { if rbacregistry.EscalationAllowed(ctx) {
return s.StandardStorage.Create(ctx, obj, includeUninitialized) return s.StandardStorage.Create(ctx, obj, createValidatingAdmission, includeUninitialized)
} }
clusterRole := obj.(*rbac.ClusterRole) clusterRole := obj.(*rbac.ClusterRole)
...@@ -50,12 +50,12 @@ func (s *Storage) Create(ctx genericapirequest.Context, obj runtime.Object, incl ...@@ -50,12 +50,12 @@ func (s *Storage) Create(ctx genericapirequest.Context, obj runtime.Object, incl
if err := rbacregistryvalidation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil { if err := rbacregistryvalidation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil {
return nil, errors.NewForbidden(groupResource, clusterRole.Name, err) return nil, errors.NewForbidden(groupResource, clusterRole.Name, err)
} }
return s.StandardStorage.Create(ctx, obj, includeUninitialized) return s.StandardStorage.Create(ctx, obj, createValidatingAdmission, includeUninitialized)
} }
func (s *Storage) Update(ctx genericapirequest.Context, name string, obj rest.UpdatedObjectInfo) (runtime.Object, bool, error) { func (s *Storage) Update(ctx genericapirequest.Context, name string, obj rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
if rbacregistry.EscalationAllowed(ctx) { if rbacregistry.EscalationAllowed(ctx) {
return s.StandardStorage.Update(ctx, name, obj) return s.StandardStorage.Update(ctx, name, obj, createValidation, updateValidation)
} }
nonEscalatingInfo := rest.WrapUpdatedObjectInfo(obj, func(ctx genericapirequest.Context, obj runtime.Object, oldObj runtime.Object) (runtime.Object, error) { nonEscalatingInfo := rest.WrapUpdatedObjectInfo(obj, func(ctx genericapirequest.Context, obj runtime.Object, oldObj runtime.Object) (runtime.Object, error) {
...@@ -73,5 +73,5 @@ func (s *Storage) Update(ctx genericapirequest.Context, name string, obj rest.Up ...@@ -73,5 +73,5 @@ func (s *Storage) Update(ctx genericapirequest.Context, name string, obj rest.Up
return obj, nil return obj, nil
}) })
return s.StandardStorage.Update(ctx, name, nonEscalatingInfo) return s.StandardStorage.Update(ctx, name, nonEscalatingInfo, createValidation, updateValidation)
} }
...@@ -28,8 +28,8 @@ import ( ...@@ -28,8 +28,8 @@ import (
// Registry is an interface for things that know how to store ClusterRoles. // Registry is an interface for things that know how to store ClusterRoles.
type Registry interface { type Registry interface {
ListClusterRoles(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*rbac.ClusterRoleList, error) ListClusterRoles(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*rbac.ClusterRoleList, error)
CreateClusterRole(ctx genericapirequest.Context, clusterRole *rbac.ClusterRole) error CreateClusterRole(ctx genericapirequest.Context, clusterRole *rbac.ClusterRole, createValidation rest.ValidateObjectFunc) error
UpdateClusterRole(ctx genericapirequest.Context, clusterRole *rbac.ClusterRole) error UpdateClusterRole(ctx genericapirequest.Context, clusterRole *rbac.ClusterRole, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) error
GetClusterRole(ctx genericapirequest.Context, name string, options *metav1.GetOptions) (*rbac.ClusterRole, error) GetClusterRole(ctx genericapirequest.Context, name string, options *metav1.GetOptions) (*rbac.ClusterRole, error)
DeleteClusterRole(ctx genericapirequest.Context, name string) error DeleteClusterRole(ctx genericapirequest.Context, name string) error
WatchClusterRoles(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error) WatchClusterRoles(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error)
...@@ -55,13 +55,13 @@ func (s *storage) ListClusterRoles(ctx genericapirequest.Context, options *metai ...@@ -55,13 +55,13 @@ func (s *storage) ListClusterRoles(ctx genericapirequest.Context, options *metai
return obj.(*rbac.ClusterRoleList), nil return obj.(*rbac.ClusterRoleList), nil
} }
func (s *storage) CreateClusterRole(ctx genericapirequest.Context, clusterRole *rbac.ClusterRole) error { func (s *storage) CreateClusterRole(ctx genericapirequest.Context, clusterRole *rbac.ClusterRole, createValidation rest.ValidateObjectFunc) error {
_, err := s.Create(ctx, clusterRole, false) _, err := s.Create(ctx, clusterRole, createValidation, false)
return err return err
} }
func (s *storage) UpdateClusterRole(ctx genericapirequest.Context, clusterRole *rbac.ClusterRole) error { func (s *storage) UpdateClusterRole(ctx genericapirequest.Context, clusterRole *rbac.ClusterRole, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) error {
_, _, err := s.Update(ctx, clusterRole.Name, rest.DefaultUpdatedObjectInfo(clusterRole)) _, _, err := s.Update(ctx, clusterRole.Name, rest.DefaultUpdatedObjectInfo(clusterRole), createValidation, updateValidation)
return err return err
} }
......
...@@ -44,14 +44,14 @@ func NewStorage(s rest.StandardStorage, authorizer authorizer.Authorizer, ruleRe ...@@ -44,14 +44,14 @@ func NewStorage(s rest.StandardStorage, authorizer authorizer.Authorizer, ruleRe
return &Storage{s, authorizer, ruleResolver} return &Storage{s, authorizer, ruleResolver}
} }
func (s *Storage) Create(ctx genericapirequest.Context, obj runtime.Object, includeUninitialized bool) (runtime.Object, error) { func (s *Storage) Create(ctx genericapirequest.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, includeUninitialized bool) (runtime.Object, error) {
if rbacregistry.EscalationAllowed(ctx) { if rbacregistry.EscalationAllowed(ctx) {
return s.StandardStorage.Create(ctx, obj, includeUninitialized) return s.StandardStorage.Create(ctx, obj, createValidation, includeUninitialized)
} }
clusterRoleBinding := obj.(*rbac.ClusterRoleBinding) clusterRoleBinding := obj.(*rbac.ClusterRoleBinding)
if rbacregistry.BindingAuthorized(ctx, clusterRoleBinding.RoleRef, metav1.NamespaceNone, s.authorizer) { if rbacregistry.BindingAuthorized(ctx, clusterRoleBinding.RoleRef, metav1.NamespaceNone, s.authorizer) {
return s.StandardStorage.Create(ctx, obj, includeUninitialized) return s.StandardStorage.Create(ctx, obj, createValidation, includeUninitialized)
} }
rules, err := s.ruleResolver.GetRoleReferenceRules(clusterRoleBinding.RoleRef, metav1.NamespaceNone) rules, err := s.ruleResolver.GetRoleReferenceRules(clusterRoleBinding.RoleRef, metav1.NamespaceNone)
...@@ -61,12 +61,12 @@ func (s *Storage) Create(ctx genericapirequest.Context, obj runtime.Object, incl ...@@ -61,12 +61,12 @@ func (s *Storage) Create(ctx genericapirequest.Context, obj runtime.Object, incl
if err := rbacregistryvalidation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil { if err := rbacregistryvalidation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil {
return nil, errors.NewForbidden(groupResource, clusterRoleBinding.Name, err) return nil, errors.NewForbidden(groupResource, clusterRoleBinding.Name, err)
} }
return s.StandardStorage.Create(ctx, obj, includeUninitialized) return s.StandardStorage.Create(ctx, obj, createValidation, includeUninitialized)
} }
func (s *Storage) Update(ctx genericapirequest.Context, name string, obj rest.UpdatedObjectInfo) (runtime.Object, bool, error) { func (s *Storage) Update(ctx genericapirequest.Context, name string, obj rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
if rbacregistry.EscalationAllowed(ctx) { if rbacregistry.EscalationAllowed(ctx) {
return s.StandardStorage.Update(ctx, name, obj) return s.StandardStorage.Update(ctx, name, obj, createValidation, updateValidation)
} }
nonEscalatingInfo := rest.WrapUpdatedObjectInfo(obj, func(ctx genericapirequest.Context, obj runtime.Object, oldObj runtime.Object) (runtime.Object, error) { nonEscalatingInfo := rest.WrapUpdatedObjectInfo(obj, func(ctx genericapirequest.Context, obj runtime.Object, oldObj runtime.Object) (runtime.Object, error) {
...@@ -93,5 +93,5 @@ func (s *Storage) Update(ctx genericapirequest.Context, name string, obj rest.Up ...@@ -93,5 +93,5 @@ func (s *Storage) Update(ctx genericapirequest.Context, name string, obj rest.Up
return obj, nil return obj, nil
}) })
return s.StandardStorage.Update(ctx, name, nonEscalatingInfo) return s.StandardStorage.Update(ctx, name, nonEscalatingInfo, createValidation, updateValidation)
} }
...@@ -28,8 +28,8 @@ import ( ...@@ -28,8 +28,8 @@ import (
// Registry is an interface for things that know how to store ClusterRoleBindings. // Registry is an interface for things that know how to store ClusterRoleBindings.
type Registry interface { type Registry interface {
ListClusterRoleBindings(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*rbac.ClusterRoleBindingList, error) ListClusterRoleBindings(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*rbac.ClusterRoleBindingList, error)
CreateClusterRoleBinding(ctx genericapirequest.Context, clusterRoleBinding *rbac.ClusterRoleBinding) error CreateClusterRoleBinding(ctx genericapirequest.Context, clusterRoleBinding *rbac.ClusterRoleBinding, createValidation rest.ValidateObjectFunc) error
UpdateClusterRoleBinding(ctx genericapirequest.Context, clusterRoleBinding *rbac.ClusterRoleBinding) error UpdateClusterRoleBinding(ctx genericapirequest.Context, clusterRoleBinding *rbac.ClusterRoleBinding, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) error
GetClusterRoleBinding(ctx genericapirequest.Context, name string, options *metav1.GetOptions) (*rbac.ClusterRoleBinding, error) GetClusterRoleBinding(ctx genericapirequest.Context, name string, options *metav1.GetOptions) (*rbac.ClusterRoleBinding, error)
DeleteClusterRoleBinding(ctx genericapirequest.Context, name string) error DeleteClusterRoleBinding(ctx genericapirequest.Context, name string) error
WatchClusterRoleBindings(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error) WatchClusterRoleBindings(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error)
...@@ -55,13 +55,13 @@ func (s *storage) ListClusterRoleBindings(ctx genericapirequest.Context, options ...@@ -55,13 +55,13 @@ func (s *storage) ListClusterRoleBindings(ctx genericapirequest.Context, options
return obj.(*rbac.ClusterRoleBindingList), nil return obj.(*rbac.ClusterRoleBindingList), nil
} }
func (s *storage) CreateClusterRoleBinding(ctx genericapirequest.Context, clusterRoleBinding *rbac.ClusterRoleBinding) error { func (s *storage) CreateClusterRoleBinding(ctx genericapirequest.Context, clusterRoleBinding *rbac.ClusterRoleBinding, createValidation rest.ValidateObjectFunc) error {
_, err := s.Create(ctx, clusterRoleBinding, false) _, err := s.Create(ctx, clusterRoleBinding, createValidation, false)
return err return err
} }
func (s *storage) UpdateClusterRoleBinding(ctx genericapirequest.Context, clusterRoleBinding *rbac.ClusterRoleBinding) error { func (s *storage) UpdateClusterRoleBinding(ctx genericapirequest.Context, clusterRoleBinding *rbac.ClusterRoleBinding, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) error {
_, _, err := s.Update(ctx, clusterRoleBinding.Name, rest.DefaultUpdatedObjectInfo(clusterRoleBinding)) _, _, err := s.Update(ctx, clusterRoleBinding.Name, rest.DefaultUpdatedObjectInfo(clusterRoleBinding), createValidation, updateValidation)
return err return err
} }
......
...@@ -40,9 +40,9 @@ func NewStorage(s rest.StandardStorage, ruleResolver rbacregistryvalidation.Auth ...@@ -40,9 +40,9 @@ func NewStorage(s rest.StandardStorage, ruleResolver rbacregistryvalidation.Auth
return &Storage{s, ruleResolver} return &Storage{s, ruleResolver}
} }
func (s *Storage) Create(ctx genericapirequest.Context, obj runtime.Object, includeUninitialized bool) (runtime.Object, error) { func (s *Storage) Create(ctx genericapirequest.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, includeUninitialized bool) (runtime.Object, error) {
if rbacregistry.EscalationAllowed(ctx) { if rbacregistry.EscalationAllowed(ctx) {
return s.StandardStorage.Create(ctx, obj, includeUninitialized) return s.StandardStorage.Create(ctx, obj, createValidation, includeUninitialized)
} }
role := obj.(*rbac.Role) role := obj.(*rbac.Role)
...@@ -50,12 +50,12 @@ func (s *Storage) Create(ctx genericapirequest.Context, obj runtime.Object, incl ...@@ -50,12 +50,12 @@ func (s *Storage) Create(ctx genericapirequest.Context, obj runtime.Object, incl
if err := rbacregistryvalidation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil { if err := rbacregistryvalidation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil {
return nil, errors.NewForbidden(groupResource, role.Name, err) return nil, errors.NewForbidden(groupResource, role.Name, err)
} }
return s.StandardStorage.Create(ctx, obj, includeUninitialized) return s.StandardStorage.Create(ctx, obj, createValidation, includeUninitialized)
} }
func (s *Storage) Update(ctx genericapirequest.Context, name string, obj rest.UpdatedObjectInfo) (runtime.Object, bool, error) { func (s *Storage) Update(ctx genericapirequest.Context, name string, obj rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
if rbacregistry.EscalationAllowed(ctx) { if rbacregistry.EscalationAllowed(ctx) {
return s.StandardStorage.Update(ctx, name, obj) return s.StandardStorage.Update(ctx, name, obj, createValidation, updateValidation)
} }
nonEscalatingInfo := rest.WrapUpdatedObjectInfo(obj, func(ctx genericapirequest.Context, obj runtime.Object, oldObj runtime.Object) (runtime.Object, error) { nonEscalatingInfo := rest.WrapUpdatedObjectInfo(obj, func(ctx genericapirequest.Context, obj runtime.Object, oldObj runtime.Object) (runtime.Object, error) {
...@@ -73,5 +73,5 @@ func (s *Storage) Update(ctx genericapirequest.Context, name string, obj rest.Up ...@@ -73,5 +73,5 @@ func (s *Storage) Update(ctx genericapirequest.Context, name string, obj rest.Up
return obj, nil return obj, nil
}) })
return s.StandardStorage.Update(ctx, name, nonEscalatingInfo) return s.StandardStorage.Update(ctx, name, nonEscalatingInfo, createValidation, updateValidation)
} }
...@@ -28,8 +28,8 @@ import ( ...@@ -28,8 +28,8 @@ import (
// Registry is an interface for things that know how to store Roles. // Registry is an interface for things that know how to store Roles.
type Registry interface { type Registry interface {
ListRoles(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*rbac.RoleList, error) ListRoles(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*rbac.RoleList, error)
CreateRole(ctx genericapirequest.Context, role *rbac.Role) error CreateRole(ctx genericapirequest.Context, role *rbac.Role, createValidation rest.ValidateObjectFunc) error
UpdateRole(ctx genericapirequest.Context, role *rbac.Role) error UpdateRole(ctx genericapirequest.Context, role *rbac.Role, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) error
GetRole(ctx genericapirequest.Context, name string, options *metav1.GetOptions) (*rbac.Role, error) GetRole(ctx genericapirequest.Context, name string, options *metav1.GetOptions) (*rbac.Role, error)
DeleteRole(ctx genericapirequest.Context, name string) error DeleteRole(ctx genericapirequest.Context, name string) error
WatchRoles(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error) WatchRoles(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error)
...@@ -55,13 +55,14 @@ func (s *storage) ListRoles(ctx genericapirequest.Context, options *metainternal ...@@ -55,13 +55,14 @@ func (s *storage) ListRoles(ctx genericapirequest.Context, options *metainternal
return obj.(*rbac.RoleList), nil return obj.(*rbac.RoleList), nil
} }
func (s *storage) CreateRole(ctx genericapirequest.Context, role *rbac.Role) error { func (s *storage) CreateRole(ctx genericapirequest.Context, role *rbac.Role, createValidation rest.ValidateObjectFunc) error {
_, err := s.Create(ctx, role, false) _, err := s.Create(ctx, role, createValidation, false)
return err return err
} }
func (s *storage) UpdateRole(ctx genericapirequest.Context, role *rbac.Role) error { func (s *storage) UpdateRole(ctx genericapirequest.Context, role *rbac.Role, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) error {
_, _, err := s.Update(ctx, role.Name, rest.DefaultUpdatedObjectInfo(role)) // TODO: any admission?
_, _, err := s.Update(ctx, role.Name, rest.DefaultUpdatedObjectInfo(role), createValidation, updateValidation)
return err return err
} }
......
...@@ -43,9 +43,9 @@ func NewStorage(s rest.StandardStorage, authorizer authorizer.Authorizer, ruleRe ...@@ -43,9 +43,9 @@ func NewStorage(s rest.StandardStorage, authorizer authorizer.Authorizer, ruleRe
return &Storage{s, authorizer, ruleResolver} return &Storage{s, authorizer, ruleResolver}
} }
func (s *Storage) Create(ctx genericapirequest.Context, obj runtime.Object, includeUninitialized bool) (runtime.Object, error) { func (s *Storage) Create(ctx genericapirequest.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, includeUninitialized bool) (runtime.Object, error) {
if rbacregistry.EscalationAllowed(ctx) { if rbacregistry.EscalationAllowed(ctx) {
return s.StandardStorage.Create(ctx, obj, includeUninitialized) return s.StandardStorage.Create(ctx, obj, createValidation, includeUninitialized)
} }
// Get the namespace from the context (populated from the URL). // Get the namespace from the context (populated from the URL).
...@@ -57,7 +57,7 @@ func (s *Storage) Create(ctx genericapirequest.Context, obj runtime.Object, incl ...@@ -57,7 +57,7 @@ func (s *Storage) Create(ctx genericapirequest.Context, obj runtime.Object, incl
roleBinding := obj.(*rbac.RoleBinding) roleBinding := obj.(*rbac.RoleBinding)
if rbacregistry.BindingAuthorized(ctx, roleBinding.RoleRef, namespace, s.authorizer) { if rbacregistry.BindingAuthorized(ctx, roleBinding.RoleRef, namespace, s.authorizer) {
return s.StandardStorage.Create(ctx, obj, includeUninitialized) return s.StandardStorage.Create(ctx, obj, createValidation, includeUninitialized)
} }
rules, err := s.ruleResolver.GetRoleReferenceRules(roleBinding.RoleRef, namespace) rules, err := s.ruleResolver.GetRoleReferenceRules(roleBinding.RoleRef, namespace)
...@@ -67,12 +67,12 @@ func (s *Storage) Create(ctx genericapirequest.Context, obj runtime.Object, incl ...@@ -67,12 +67,12 @@ func (s *Storage) Create(ctx genericapirequest.Context, obj runtime.Object, incl
if err := rbacregistryvalidation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil { if err := rbacregistryvalidation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil {
return nil, errors.NewForbidden(groupResource, roleBinding.Name, err) return nil, errors.NewForbidden(groupResource, roleBinding.Name, err)
} }
return s.StandardStorage.Create(ctx, obj, includeUninitialized) return s.StandardStorage.Create(ctx, obj, createValidation, includeUninitialized)
} }
func (s *Storage) Update(ctx genericapirequest.Context, name string, obj rest.UpdatedObjectInfo) (runtime.Object, bool, error) { func (s *Storage) Update(ctx genericapirequest.Context, name string, obj rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
if rbacregistry.EscalationAllowed(ctx) { if rbacregistry.EscalationAllowed(ctx) {
return s.StandardStorage.Update(ctx, name, obj) return s.StandardStorage.Update(ctx, name, obj, createValidation, updateValidation)
} }
nonEscalatingInfo := rest.WrapUpdatedObjectInfo(obj, func(ctx genericapirequest.Context, obj runtime.Object, oldObj runtime.Object) (runtime.Object, error) { nonEscalatingInfo := rest.WrapUpdatedObjectInfo(obj, func(ctx genericapirequest.Context, obj runtime.Object, oldObj runtime.Object) (runtime.Object, error) {
...@@ -106,5 +106,5 @@ func (s *Storage) Update(ctx genericapirequest.Context, name string, obj rest.Up ...@@ -106,5 +106,5 @@ func (s *Storage) Update(ctx genericapirequest.Context, name string, obj rest.Up
return obj, nil return obj, nil
}) })
return s.StandardStorage.Update(ctx, name, nonEscalatingInfo) return s.StandardStorage.Update(ctx, name, nonEscalatingInfo, createValidation, updateValidation)
} }
...@@ -28,8 +28,8 @@ import ( ...@@ -28,8 +28,8 @@ import (
// Registry is an interface for things that know how to store RoleBindings. // Registry is an interface for things that know how to store RoleBindings.
type Registry interface { type Registry interface {
ListRoleBindings(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*rbac.RoleBindingList, error) ListRoleBindings(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*rbac.RoleBindingList, error)
CreateRoleBinding(ctx genericapirequest.Context, roleBinding *rbac.RoleBinding) error CreateRoleBinding(ctx genericapirequest.Context, roleBinding *rbac.RoleBinding, createValidation rest.ValidateObjectFunc) error
UpdateRoleBinding(ctx genericapirequest.Context, roleBinding *rbac.RoleBinding) error UpdateRoleBinding(ctx genericapirequest.Context, roleBinding *rbac.RoleBinding, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) error
GetRoleBinding(ctx genericapirequest.Context, name string, options *metav1.GetOptions) (*rbac.RoleBinding, error) GetRoleBinding(ctx genericapirequest.Context, name string, options *metav1.GetOptions) (*rbac.RoleBinding, error)
DeleteRoleBinding(ctx genericapirequest.Context, name string) error DeleteRoleBinding(ctx genericapirequest.Context, name string) error
WatchRoleBindings(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error) WatchRoleBindings(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error)
...@@ -55,14 +55,14 @@ func (s *storage) ListRoleBindings(ctx genericapirequest.Context, options *metai ...@@ -55,14 +55,14 @@ func (s *storage) ListRoleBindings(ctx genericapirequest.Context, options *metai
return obj.(*rbac.RoleBindingList), nil return obj.(*rbac.RoleBindingList), nil
} }
func (s *storage) CreateRoleBinding(ctx genericapirequest.Context, roleBinding *rbac.RoleBinding) error { func (s *storage) CreateRoleBinding(ctx genericapirequest.Context, roleBinding *rbac.RoleBinding, createValidation rest.ValidateObjectFunc) error {
// TODO(ericchiang): add additional validation // TODO(ericchiang): add additional validation
_, err := s.Create(ctx, roleBinding, false) _, err := s.Create(ctx, roleBinding, createValidation, false)
return err return err
} }
func (s *storage) UpdateRoleBinding(ctx genericapirequest.Context, roleBinding *rbac.RoleBinding) error { func (s *storage) UpdateRoleBinding(ctx genericapirequest.Context, roleBinding *rbac.RoleBinding, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) error {
_, _, err := s.Update(ctx, roleBinding.Name, rest.DefaultUpdatedObjectInfo(roleBinding)) _, _, err := s.Update(ctx, roleBinding.Name, rest.DefaultUpdatedObjectInfo(roleBinding), createValidation, updateValidation)
return err return err
} }
......
...@@ -25,6 +25,7 @@ import ( ...@@ -25,6 +25,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch" "k8s.io/apimachinery/pkg/watch"
genericapirequest "k8s.io/apiserver/pkg/endpoints/request" genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/registry/rest"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
) )
...@@ -66,7 +67,7 @@ func (e *EndpointRegistry) WatchEndpoints(ctx genericapirequest.Context, options ...@@ -66,7 +67,7 @@ func (e *EndpointRegistry) WatchEndpoints(ctx genericapirequest.Context, options
return nil, fmt.Errorf("unimplemented!") return nil, fmt.Errorf("unimplemented!")
} }
func (e *EndpointRegistry) UpdateEndpoints(ctx genericapirequest.Context, endpoints *api.Endpoints) error { func (e *EndpointRegistry) UpdateEndpoints(ctx genericapirequest.Context, endpoints *api.Endpoints, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) error {
// TODO: support namespaces in this mock // TODO: support namespaces in this mock
e.lock.Lock() e.lock.Lock()
defer e.lock.Unlock() defer e.lock.Unlock()
......
...@@ -23,6 +23,7 @@ import ( ...@@ -23,6 +23,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch" "k8s.io/apimachinery/pkg/watch"
genericapirequest "k8s.io/apiserver/pkg/endpoints/request" genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/registry/rest"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
) )
...@@ -72,7 +73,7 @@ func (r *ServiceRegistry) ListServices(ctx genericapirequest.Context, options *m ...@@ -72,7 +73,7 @@ func (r *ServiceRegistry) ListServices(ctx genericapirequest.Context, options *m
return res, r.Err return res, r.Err
} }
func (r *ServiceRegistry) CreateService(ctx genericapirequest.Context, svc *api.Service) (*api.Service, error) { func (r *ServiceRegistry) CreateService(ctx genericapirequest.Context, svc *api.Service, createValidation rest.ValidateObjectFunc) (*api.Service, error) {
r.mu.Lock() r.mu.Lock()
defer r.mu.Unlock() defer r.mu.Unlock()
...@@ -99,7 +100,7 @@ func (r *ServiceRegistry) DeleteService(ctx genericapirequest.Context, id string ...@@ -99,7 +100,7 @@ func (r *ServiceRegistry) DeleteService(ctx genericapirequest.Context, id string
return r.Err return r.Err
} }
func (r *ServiceRegistry) UpdateService(ctx genericapirequest.Context, svc *api.Service) (*api.Service, error) { func (r *ServiceRegistry) UpdateService(ctx genericapirequest.Context, svc *api.Service, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (*api.Service, error) {
r.mu.Lock() r.mu.Lock()
defer r.mu.Unlock() defer r.mu.Unlock()
......
...@@ -28,8 +28,8 @@ import ( ...@@ -28,8 +28,8 @@ import (
// Registry is an interface for things that know how to store PriorityClass. // Registry is an interface for things that know how to store PriorityClass.
type Registry interface { type Registry interface {
ListPriorityClasses(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*scheduling.PriorityClassList, error) ListPriorityClasses(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*scheduling.PriorityClassList, error)
CreatePriorityClass(ctx genericapirequest.Context, pc *scheduling.PriorityClass) error CreatePriorityClass(ctx genericapirequest.Context, pc *scheduling.PriorityClass, createValidation rest.ValidateObjectFunc) error
UpdatePriorityClass(ctx genericapirequest.Context, pc *scheduling.PriorityClass) error UpdatePriorityClass(ctx genericapirequest.Context, pc *scheduling.PriorityClass, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) error
GetPriorityClass(ctx genericapirequest.Context, name string, options *metav1.GetOptions) (*scheduling.PriorityClass, error) GetPriorityClass(ctx genericapirequest.Context, name string, options *metav1.GetOptions) (*scheduling.PriorityClass, error)
DeletePriorityClass(ctx genericapirequest.Context, name string) error DeletePriorityClass(ctx genericapirequest.Context, name string) error
WatchPriorityClasses(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error) WatchPriorityClasses(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error)
...@@ -55,13 +55,13 @@ func (s *storage) ListPriorityClasses(ctx genericapirequest.Context, options *me ...@@ -55,13 +55,13 @@ func (s *storage) ListPriorityClasses(ctx genericapirequest.Context, options *me
return obj.(*scheduling.PriorityClassList), nil return obj.(*scheduling.PriorityClassList), nil
} }
func (s *storage) CreatePriorityClass(ctx genericapirequest.Context, pc *scheduling.PriorityClass) error { func (s *storage) CreatePriorityClass(ctx genericapirequest.Context, pc *scheduling.PriorityClass, createValidation rest.ValidateObjectFunc) error {
_, err := s.Create(ctx, pc, false) _, err := s.Create(ctx, pc, createValidation, false)
return err return err
} }
func (s *storage) UpdatePriorityClass(ctx genericapirequest.Context, pc *scheduling.PriorityClass) error { func (s *storage) UpdatePriorityClass(ctx genericapirequest.Context, pc *scheduling.PriorityClass, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) error {
_, _, err := s.Update(ctx, pc.Name, rest.DefaultUpdatedObjectInfo(pc)) _, _, err := s.Update(ctx, pc.Name, rest.DefaultUpdatedObjectInfo(pc), createValidation, updateValidation)
return err return err
} }
......
...@@ -28,8 +28,8 @@ import ( ...@@ -28,8 +28,8 @@ import (
// Registry is an interface for things that know how to store PodPresets. // Registry is an interface for things that know how to store PodPresets.
type Registry interface { type Registry interface {
ListPodPresets(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*settings.PodPresetList, error) ListPodPresets(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (*settings.PodPresetList, error)
CreatePodPreset(ctx genericapirequest.Context, pp *settings.PodPreset) error CreatePodPreset(ctx genericapirequest.Context, pp *settings.PodPreset, createValidation rest.ValidateObjectFunc) error
UpdatePodPreset(ctx genericapirequest.Context, pp *settings.PodPreset) error UpdatePodPreset(ctx genericapirequest.Context, pp *settings.PodPreset, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) error
GetPodPreset(ctx genericapirequest.Context, ppID string, options *metav1.GetOptions) (*settings.PodPreset, error) GetPodPreset(ctx genericapirequest.Context, ppID string, options *metav1.GetOptions) (*settings.PodPreset, error)
DeletePodPreset(ctx genericapirequest.Context, ppID string) error DeletePodPreset(ctx genericapirequest.Context, ppID string) error
WatchPodPresets(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error) WatchPodPresets(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error)
...@@ -55,13 +55,13 @@ func (s *storage) ListPodPresets(ctx genericapirequest.Context, options *metaint ...@@ -55,13 +55,13 @@ func (s *storage) ListPodPresets(ctx genericapirequest.Context, options *metaint
return obj.(*settings.PodPresetList), nil return obj.(*settings.PodPresetList), nil
} }
func (s *storage) CreatePodPreset(ctx genericapirequest.Context, pp *settings.PodPreset) error { func (s *storage) CreatePodPreset(ctx genericapirequest.Context, pp *settings.PodPreset, createValidation rest.ValidateObjectFunc) error {
_, err := s.Create(ctx, pp, false) _, err := s.Create(ctx, pp, createValidation, false)
return err return err
} }
func (s *storage) UpdatePodPreset(ctx genericapirequest.Context, pp *settings.PodPreset) error { func (s *storage) UpdatePodPreset(ctx genericapirequest.Context, pp *settings.PodPreset, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) error {
_, _, err := s.Update(ctx, pp.Name, rest.DefaultUpdatedObjectInfo(pp)) _, _, err := s.Update(ctx, pp.Name, rest.DefaultUpdatedObjectInfo(pp), createValidation, updateValidation)
return err return err
} }
......
...@@ -38,6 +38,11 @@ func (AlwaysAdmit) Admit(a admission.Attributes) (err error) { ...@@ -38,6 +38,11 @@ func (AlwaysAdmit) Admit(a admission.Attributes) (err error) {
return nil return nil
} }
// Validate makes an admission decision based on the request attributes. It is NOT allowed to mutate.
func (AlwaysAdmit) Validate(a admission.Attributes) (err error) {
return nil
}
// Handles returns true if this admission controller can handle the given operation // Handles returns true if this admission controller can handle the given operation
// where operation can be one of CREATE, UPDATE, DELETE, or CONNECT // where operation can be one of CREATE, UPDATE, DELETE, or CONNECT
func (AlwaysAdmit) Handles(operation admission.Operation) bool { func (AlwaysAdmit) Handles(operation admission.Operation) bool {
......
...@@ -135,8 +135,8 @@ func (d *DenyExec) SetInternalKubeClientSet(client internalclientset.Interface) ...@@ -135,8 +135,8 @@ func (d *DenyExec) SetInternalKubeClientSet(client internalclientset.Interface)
d.client = client d.client = client
} }
// Validate implements the Validator interface. // ValidateInitialization implements the InitializationValidator interface.
func (d *DenyExec) Validate() error { func (d *DenyExec) ValidateInitialization() error {
if d.client == nil { if d.client == nil {
return fmt.Errorf("missing client") return fmt.Errorf("missing client")
} }
......
...@@ -118,7 +118,7 @@ func testAdmission(t *testing.T, pod *api.Pod, handler *DenyExec, shouldAccept b ...@@ -118,7 +118,7 @@ func testAdmission(t *testing.T, pod *api.Pod, handler *DenyExec, shouldAccept b
}) })
handler.SetInternalKubeClientSet(mockClient) handler.SetInternalKubeClientSet(mockClient)
admission.Validate(handler) admission.ValidateInitialization(handler)
// pods/exec // pods/exec
{ {
......
...@@ -260,7 +260,7 @@ func (a *gcPermissionsEnforcement) SetRESTMapper(restMapper meta.RESTMapper) { ...@@ -260,7 +260,7 @@ func (a *gcPermissionsEnforcement) SetRESTMapper(restMapper meta.RESTMapper) {
a.restMapper = restMapper a.restMapper = restMapper
} }
func (a *gcPermissionsEnforcement) Validate() error { func (a *gcPermissionsEnforcement) ValidateInitialization() error {
if a.authorizer == nil { if a.authorizer == nil {
return fmt.Errorf("missing authorizer") return fmt.Errorf("missing authorizer")
} }
......
...@@ -110,7 +110,7 @@ func expectNoAnnotation(t *testing.T, pod *api.Pod) { ...@@ -110,7 +110,7 @@ func expectNoAnnotation(t *testing.T, pod *api.Pod) {
} }
} }
func admit(t *testing.T, ir admission.Interface, pods []*api.Pod) { func admit(t *testing.T, ir admission.MutationInterface, pods []*api.Pod) {
for i := range pods { for i := range pods {
p := pods[i] p := pods[i]
...@@ -123,7 +123,7 @@ func admit(t *testing.T, ir admission.Interface, pods []*api.Pod) { ...@@ -123,7 +123,7 @@ func admit(t *testing.T, ir admission.Interface, pods []*api.Pod) {
} }
} }
func testAdminScenarios(t *testing.T, ir admission.Interface, p *api.Pod) { func testAdminScenarios(t *testing.T, ir admission.MutationInterface, p *api.Pod) {
podKind := api.Kind("Pod").WithVersion("version") podKind := api.Kind("Pod").WithVersion("version")
podRes := api.Resource("pods").WithVersion("version") podRes := api.Resource("pods").WithVersion("version")
...@@ -151,7 +151,7 @@ func testAdminScenarios(t *testing.T, ir admission.Interface, p *api.Pod) { ...@@ -151,7 +151,7 @@ func testAdminScenarios(t *testing.T, ir admission.Interface, p *api.Pod) {
} }
} }
func performTest(t *testing.T, ir admission.Interface) { func performTest(t *testing.T, ir admission.MutationInterface) {
pods := getPods() pods := getPods()
admit(t, ir, pods) admit(t, ir, pods)
testAdminScenarios(t, ir, pods[0]) testAdminScenarios(t, ir, pods[0])
......
...@@ -75,7 +75,7 @@ func (l *LimitRanger) SetInternalKubeInformerFactory(f informers.SharedInformerF ...@@ -75,7 +75,7 @@ func (l *LimitRanger) SetInternalKubeInformerFactory(f informers.SharedInformerF
l.lister = limitRangeInformer.Lister() l.lister = limitRangeInformer.Lister()
} }
func (l *LimitRanger) Validate() error { func (l *LimitRanger) ValidateInitialization() error {
if l.lister == nil { if l.lister == nil {
return fmt.Errorf("missing limitRange lister") return fmt.Errorf("missing limitRange lister")
} }
......
...@@ -746,7 +746,7 @@ func newHandlerForTest(c clientset.Interface) (*LimitRanger, informers.SharedInf ...@@ -746,7 +746,7 @@ func newHandlerForTest(c clientset.Interface) (*LimitRanger, informers.SharedInf
} }
pluginInitializer := kubeadmission.NewPluginInitializer(c, f, nil, nil, nil, nil, nil) pluginInitializer := kubeadmission.NewPluginInitializer(c, f, nil, nil, nil, nil, nil)
pluginInitializer.Initialize(handler) pluginInitializer.Initialize(handler)
err = admission.Validate(handler) err = admission.ValidateInitialization(handler)
return handler, f, err return handler, f, err
} }
......
...@@ -106,8 +106,8 @@ func (p *Provision) SetInternalKubeInformerFactory(f informers.SharedInformerFac ...@@ -106,8 +106,8 @@ func (p *Provision) SetInternalKubeInformerFactory(f informers.SharedInformerFac
p.SetReadyFunc(namespaceInformer.Informer().HasSynced) p.SetReadyFunc(namespaceInformer.Informer().HasSynced)
} }
// Validate implements the Validator interface. // ValidateInitialization implements the InitializationValidator interface.
func (p *Provision) Validate() error { func (p *Provision) ValidateInitialization() error {
if p.namespaceLister == nil { if p.namespaceLister == nil {
return fmt.Errorf("missing namespaceLister") return fmt.Errorf("missing namespaceLister")
} }
......
...@@ -35,12 +35,12 @@ import ( ...@@ -35,12 +35,12 @@ import (
) )
// newHandlerForTest returns the admission controller configured for testing. // newHandlerForTest returns the admission controller configured for testing.
func newHandlerForTest(c clientset.Interface) (admission.Interface, informers.SharedInformerFactory, error) { func newHandlerForTest(c clientset.Interface) (admission.MutationInterface, informers.SharedInformerFactory, error) {
f := informers.NewSharedInformerFactory(c, 5*time.Minute) f := informers.NewSharedInformerFactory(c, 5*time.Minute)
handler := NewProvision() handler := NewProvision()
pluginInitializer := kubeadmission.NewPluginInitializer(c, f, nil, nil, nil, nil, nil) pluginInitializer := kubeadmission.NewPluginInitializer(c, f, nil, nil, nil, nil, nil)
pluginInitializer.Initialize(handler) pluginInitializer.Initialize(handler)
err := admission.Validate(handler) err := admission.ValidateInitialization(handler)
return handler, f, err return handler, f, err
} }
......
...@@ -101,8 +101,8 @@ func (e *Exists) SetInternalKubeInformerFactory(f informers.SharedInformerFactor ...@@ -101,8 +101,8 @@ func (e *Exists) SetInternalKubeInformerFactory(f informers.SharedInformerFactor
e.SetReadyFunc(namespaceInformer.Informer().HasSynced) e.SetReadyFunc(namespaceInformer.Informer().HasSynced)
} }
// Validate implements the Validator interface. // ValidateInitialization implements the InitializationValidator interface.
func (e *Exists) Validate() error { func (e *Exists) ValidateInitialization() error {
if e.namespaceLister == nil { if e.namespaceLister == nil {
return fmt.Errorf("missing namespaceLister") return fmt.Errorf("missing namespaceLister")
} }
......
...@@ -34,12 +34,12 @@ import ( ...@@ -34,12 +34,12 @@ import (
) )
// newHandlerForTest returns the admission controller configured for testing. // newHandlerForTest returns the admission controller configured for testing.
func newHandlerForTest(c clientset.Interface) (admission.Interface, informers.SharedInformerFactory, error) { func newHandlerForTest(c clientset.Interface) (admission.MutationInterface, informers.SharedInformerFactory, error) {
f := informers.NewSharedInformerFactory(c, 5*time.Minute) f := informers.NewSharedInformerFactory(c, 5*time.Minute)
handler := NewExists() handler := NewExists()
pluginInitializer := kubeadmission.NewPluginInitializer(c, f, nil, nil, nil, nil, nil) pluginInitializer := kubeadmission.NewPluginInitializer(c, f, nil, nil, nil, nil, nil)
pluginInitializer.Initialize(handler) pluginInitializer.Initialize(handler)
err := admission.Validate(handler) err := admission.ValidateInitialization(handler)
return handler, f, err return handler, f, err
} }
......
...@@ -69,7 +69,7 @@ func (p *nodePlugin) SetInternalKubeClientSet(f internalclientset.Interface) { ...@@ -69,7 +69,7 @@ func (p *nodePlugin) SetInternalKubeClientSet(f internalclientset.Interface) {
p.podsGetter = f.Core() p.podsGetter = f.Core()
} }
func (p *nodePlugin) Validate() error { func (p *nodePlugin) ValidateInitialization() error {
if p.nodeIdentifier == nil { if p.nodeIdentifier == nil {
return fmt.Errorf("%s requires a node identifier", PluginName) return fmt.Errorf("%s requires a node identifier", PluginName)
} }
......
...@@ -68,8 +68,8 @@ func (pvcr *persistentVolumeClaimResize) SetInternalKubeInformerFactory(f inform ...@@ -68,8 +68,8 @@ func (pvcr *persistentVolumeClaimResize) SetInternalKubeInformerFactory(f inform
}) })
} }
// Validate ensures lister is set. // ValidateInitialization ensures lister is set.
func (pvcr *persistentVolumeClaimResize) Validate() error { func (pvcr *persistentVolumeClaimResize) ValidateInitialization() error {
if pvcr.pvLister == nil { if pvcr.pvLister == nil {
return fmt.Errorf("missing persistent volume lister") return fmt.Errorf("missing persistent volume lister")
} }
......
...@@ -272,7 +272,7 @@ func TestPVCResizeAdmission(t *testing.T) { ...@@ -272,7 +272,7 @@ func TestPVCResizeAdmission(t *testing.T) {
ctrl := newPlugin() ctrl := newPlugin()
informerFactory := informers.NewSharedInformerFactory(nil, controller.NoResyncPeriodFunc()) informerFactory := informers.NewSharedInformerFactory(nil, controller.NoResyncPeriodFunc())
ctrl.SetInternalKubeInformerFactory(informerFactory) ctrl.SetInternalKubeInformerFactory(informerFactory)
err := ctrl.Validate() err := ctrl.ValidateInitialization()
if err != nil { if err != nil {
t.Fatalf("neither pv lister nor storageclass lister can be nil") t.Fatalf("neither pv lister nor storageclass lister can be nil")
} }
......
...@@ -183,7 +183,7 @@ func (p *podNodeSelector) SetInternalKubeInformerFactory(f informers.SharedInfor ...@@ -183,7 +183,7 @@ func (p *podNodeSelector) SetInternalKubeInformerFactory(f informers.SharedInfor
p.SetReadyFunc(namespaceInformer.Informer().HasSynced) p.SetReadyFunc(namespaceInformer.Informer().HasSynced)
} }
func (p *podNodeSelector) Validate() error { func (p *podNodeSelector) ValidateInitialization() error {
if p.namespaceLister == nil { if p.namespaceLister == nil {
return fmt.Errorf("missing namespaceLister") return fmt.Errorf("missing namespaceLister")
} }
......
...@@ -243,6 +243,6 @@ func newHandlerForTest(c clientset.Interface) (*podNodeSelector, informers.Share ...@@ -243,6 +243,6 @@ func newHandlerForTest(c clientset.Interface) (*podNodeSelector, informers.Share
handler := NewPodNodeSelector(nil) handler := NewPodNodeSelector(nil)
pluginInitializer := kubeadmission.NewPluginInitializer(c, f, nil, nil, nil, nil, nil) pluginInitializer := kubeadmission.NewPluginInitializer(c, f, nil, nil, nil, nil, nil)
pluginInitializer.Initialize(handler) pluginInitializer.Initialize(handler)
err := admission.Validate(handler) err := admission.ValidateInitialization(handler)
return handler, f, err return handler, f, err
} }
...@@ -69,7 +69,7 @@ func NewPlugin() *podPresetPlugin { ...@@ -69,7 +69,7 @@ func NewPlugin() *podPresetPlugin {
} }
} }
func (plugin *podPresetPlugin) Validate() error { func (plugin *podPresetPlugin) ValidateInitialization() error {
if plugin.client == nil { if plugin.client == nil {
return fmt.Errorf("%s requires a client", pluginName) return fmt.Errorf("%s requires a client", pluginName)
} }
......
...@@ -393,7 +393,7 @@ func TestMergeVolumes(t *testing.T) { ...@@ -393,7 +393,7 @@ func TestMergeVolumes(t *testing.T) {
// NewTestAdmission provides an admission plugin with test implementations of internal structs. It uses // NewTestAdmission provides an admission plugin with test implementations of internal structs. It uses
// an authorizer that always returns true. // an authorizer that always returns true.
func NewTestAdmission(lister settingslisters.PodPresetLister, objects ...runtime.Object) kadmission.Interface { func NewTestAdmission(lister settingslisters.PodPresetLister, objects ...runtime.Object) kadmission.MutationInterface {
// Build a test client that the admission plugin can use to look up the service account missing from its cache // Build a test client that the admission plugin can use to look up the service account missing from its cache
client := fake.NewSimpleClientset(objects...) client := fake.NewSimpleClientset(objects...)
......
...@@ -202,7 +202,7 @@ func (p *podTolerationsPlugin) SetInternalKubeInformerFactory(f informers.Shared ...@@ -202,7 +202,7 @@ func (p *podTolerationsPlugin) SetInternalKubeInformerFactory(f informers.Shared
} }
func (p *podTolerationsPlugin) Validate() error { func (p *podTolerationsPlugin) ValidateInitialization() error {
if p.namespaceLister == nil { if p.namespaceLister == nil {
return fmt.Errorf("missing namespaceLister") return fmt.Errorf("missing namespaceLister")
} }
......
...@@ -363,6 +363,6 @@ func newHandlerForTest(c clientset.Interface) (*podTolerationsPlugin, informers. ...@@ -363,6 +363,6 @@ func newHandlerForTest(c clientset.Interface) (*podTolerationsPlugin, informers.
handler := NewPodTolerationsPlugin(pluginConfig) handler := NewPodTolerationsPlugin(pluginConfig)
pluginInitializer := kubeadmission.NewPluginInitializer(c, f, nil, nil, nil, nil, nil) pluginInitializer := kubeadmission.NewPluginInitializer(c, f, nil, nil, nil, nil, nil)
pluginInitializer.Initialize(handler) pluginInitializer.Initialize(handler)
err = admission.Validate(handler) err = admission.ValidateInitialization(handler)
return handler, f, err return handler, f, err
} }
...@@ -74,8 +74,8 @@ func NewPlugin() *PriorityPlugin { ...@@ -74,8 +74,8 @@ func NewPlugin() *PriorityPlugin {
} }
} }
// Validate implements the Validator interface. // ValidateInitialization implements the InitializationValidator interface.
func (p *PriorityPlugin) Validate() error { func (p *PriorityPlugin) ValidateInitialization() error {
if p.client == nil { if p.client == nil {
return fmt.Errorf("%s requires a client", pluginName) return fmt.Errorf("%s requires a client", pluginName)
} }
......
...@@ -100,8 +100,8 @@ func (a *QuotaAdmission) SetQuotaConfiguration(c quota.Configuration) { ...@@ -100,8 +100,8 @@ func (a *QuotaAdmission) SetQuotaConfiguration(c quota.Configuration) {
a.evaluator = NewQuotaEvaluator(a.quotaAccessor, a.quotaConfiguration, nil, a.config, a.numEvaluators, a.stopCh) a.evaluator = NewQuotaEvaluator(a.quotaAccessor, a.quotaConfiguration, nil, a.config, a.numEvaluators, a.stopCh)
} }
// Validate ensures an authorizer is set. // ValidateInitialization ensures an authorizer is set.
func (a *QuotaAdmission) Validate() error { func (a *QuotaAdmission) ValidateInitialization() error {
if a.quotaAccessor == nil { if a.quotaAccessor == nil {
return fmt.Errorf("missing quotaAccessor") return fmt.Errorf("missing quotaAccessor")
} }
......
...@@ -72,8 +72,8 @@ func (plugin *podSecurityPolicyPlugin) SetAuthorizer(authz authorizer.Authorizer ...@@ -72,8 +72,8 @@ func (plugin *podSecurityPolicyPlugin) SetAuthorizer(authz authorizer.Authorizer
plugin.authz = authz plugin.authz = authz
} }
// Validate ensures an authorizer is set. // ValidateInitialization ensures an authorizer is set.
func (plugin *podSecurityPolicyPlugin) Validate() error { func (plugin *podSecurityPolicyPlugin) ValidateInitialization() error {
if plugin.authz == nil { if plugin.authz == nil {
return fmt.Errorf("%s requires an authorizer", PluginName) return fmt.Errorf("%s requires an authorizer", PluginName)
} }
......
...@@ -49,7 +49,7 @@ const defaultContainerName = "test-c" ...@@ -49,7 +49,7 @@ const defaultContainerName = "test-c"
// NewTestAdmission provides an admission plugin with test implementations of internal structs. It uses // NewTestAdmission provides an admission plugin with test implementations of internal structs. It uses
// an authorizer that always returns true. // an authorizer that always returns true.
func NewTestAdmission(lister extensionslisters.PodSecurityPolicyLister) kadmission.Interface { func NewTestAdmission(lister extensionslisters.PodSecurityPolicyLister) kadmission.MutationInterface {
return &podSecurityPolicyPlugin{ return &podSecurityPolicyPlugin{
Handler: kadmission.NewHandler(kadmission.Create, kadmission.Update), Handler: kadmission.NewHandler(kadmission.Create, kadmission.Update),
strategyFactory: kpsp.NewSimpleStrategyFactory(), strategyFactory: kpsp.NewSimpleStrategyFactory(),
......
...@@ -117,8 +117,8 @@ func (a *serviceAccount) SetInternalKubeInformerFactory(f informers.SharedInform ...@@ -117,8 +117,8 @@ func (a *serviceAccount) SetInternalKubeInformerFactory(f informers.SharedInform
}) })
} }
// Validate ensures an authorizer is set. // ValidateInitialization ensures an authorizer is set.
func (a *serviceAccount) Validate() error { func (a *serviceAccount) ValidateInitialization() error {
if a.client == nil { if a.client == nil {
return fmt.Errorf("missing client") return fmt.Errorf("missing client")
} }
......
...@@ -69,8 +69,8 @@ func (a *claimDefaulterPlugin) SetInternalKubeInformerFactory(f informers.Shared ...@@ -69,8 +69,8 @@ func (a *claimDefaulterPlugin) SetInternalKubeInformerFactory(f informers.Shared
a.SetReadyFunc(informer.Informer().HasSynced) a.SetReadyFunc(informer.Informer().HasSynced)
} }
// Validate ensures lister is set. // ValidateInitialization ensures lister is set.
func (a *claimDefaulterPlugin) Validate() error { func (a *claimDefaulterPlugin) ValidateInitialization() error {
if a.lister == nil { if a.lister == nil {
return fmt.Errorf("missing lister") return fmt.Errorf("missing lister")
} }
......
...@@ -167,6 +167,6 @@ func (r *StatusREST) New() runtime.Object { ...@@ -167,6 +167,6 @@ func (r *StatusREST) New() runtime.Object {
} }
// Update alters the status subset of an object. // Update alters the status subset of an object.
func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo) return r.store.Update(ctx, name, objInfo, createValidation, updateValidation)
} }
...@@ -30,11 +30,29 @@ func (admissionHandler chainAdmissionHandler) Admit(a Attributes) error { ...@@ -30,11 +30,29 @@ func (admissionHandler chainAdmissionHandler) Admit(a Attributes) error {
if !handler.Handles(a.GetOperation()) { if !handler.Handles(a.GetOperation()) {
continue continue
} }
err := handler.Admit(a) if mutator, ok := handler.(MutationInterface); ok {
err := mutator.Admit(a)
if err != nil { if err != nil {
return err return err
} }
} }
}
return nil
}
// Validate performs an admission control check using a chain of handlers, and returns immediately on first error
func (admissionHandler chainAdmissionHandler) Validate(a Attributes) error {
for _, handler := range admissionHandler {
if !handler.Handles(a.GetOperation()) {
continue
}
if validator, ok := handler.(ValidationInterface); ok {
err := validator.Validate(a)
if err != nil {
return err
}
}
}
return nil return nil
} }
......
...@@ -26,8 +26,8 @@ import ( ...@@ -26,8 +26,8 @@ import (
type FakeHandler struct { type FakeHandler struct {
*Handler *Handler
name string name string
admit bool admit, admitCalled bool
admitCalled bool validate, validateCalled bool
} }
func (h *FakeHandler) Admit(a Attributes) (err error) { func (h *FakeHandler) Admit(a Attributes) (err error) {
...@@ -38,6 +38,14 @@ func (h *FakeHandler) Admit(a Attributes) (err error) { ...@@ -38,6 +38,14 @@ func (h *FakeHandler) Admit(a Attributes) (err error) {
return fmt.Errorf("Don't admit") return fmt.Errorf("Don't admit")
} }
func (h *FakeHandler) Validate(a Attributes) (err error) {
h.admitCalled = true
if h.admit {
return nil
}
return fmt.Errorf("Don't admit")
}
func makeHandler(name string, admit bool, ops ...Operation) Interface { func makeHandler(name string, admit bool, ops ...Operation) Interface {
return &FakeHandler{ return &FakeHandler{
name: name, name: name,
......
...@@ -99,7 +99,7 @@ func (self *WantExternalKubeInformerFactory) SetExternalKubeInformerFactory(sf i ...@@ -99,7 +99,7 @@ func (self *WantExternalKubeInformerFactory) SetExternalKubeInformerFactory(sf i
} }
func (self *WantExternalKubeInformerFactory) Admit(a admission.Attributes) error { return nil } func (self *WantExternalKubeInformerFactory) Admit(a admission.Attributes) error { return nil }
func (self *WantExternalKubeInformerFactory) Handles(o admission.Operation) bool { return false } func (self *WantExternalKubeInformerFactory) Handles(o admission.Operation) bool { return false }
func (self *WantExternalKubeInformerFactory) Validate() error { return nil } func (self *WantExternalKubeInformerFactory) ValidateInitialization() error { return nil }
var _ admission.Interface = &WantExternalKubeInformerFactory{} var _ admission.Interface = &WantExternalKubeInformerFactory{}
var _ initializer.WantsExternalKubeInformerFactory = &WantExternalKubeInformerFactory{} var _ initializer.WantsExternalKubeInformerFactory = &WantExternalKubeInformerFactory{}
...@@ -112,7 +112,7 @@ type WantExternalKubeClientSet struct { ...@@ -112,7 +112,7 @@ type WantExternalKubeClientSet struct {
func (self *WantExternalKubeClientSet) SetExternalKubeClientSet(cs kubernetes.Interface) { self.cs = cs } func (self *WantExternalKubeClientSet) SetExternalKubeClientSet(cs kubernetes.Interface) { self.cs = cs }
func (self *WantExternalKubeClientSet) Admit(a admission.Attributes) error { return nil } func (self *WantExternalKubeClientSet) Admit(a admission.Attributes) error { return nil }
func (self *WantExternalKubeClientSet) Handles(o admission.Operation) bool { return false } func (self *WantExternalKubeClientSet) Handles(o admission.Operation) bool { return false }
func (self *WantExternalKubeClientSet) Validate() error { return nil } func (self *WantExternalKubeClientSet) ValidateInitialization() error { return nil }
var _ admission.Interface = &WantExternalKubeClientSet{} var _ admission.Interface = &WantExternalKubeClientSet{}
var _ initializer.WantsExternalKubeClientSet = &WantExternalKubeClientSet{} var _ initializer.WantsExternalKubeClientSet = &WantExternalKubeClientSet{}
...@@ -125,7 +125,7 @@ type WantAuthorizerAdmission struct { ...@@ -125,7 +125,7 @@ type WantAuthorizerAdmission struct {
func (self *WantAuthorizerAdmission) SetAuthorizer(a authorizer.Authorizer) { self.auth = a } func (self *WantAuthorizerAdmission) SetAuthorizer(a authorizer.Authorizer) { self.auth = a }
func (self *WantAuthorizerAdmission) Admit(a admission.Attributes) error { return nil } func (self *WantAuthorizerAdmission) Admit(a admission.Attributes) error { return nil }
func (self *WantAuthorizerAdmission) Handles(o admission.Operation) bool { return false } func (self *WantAuthorizerAdmission) Handles(o admission.Operation) bool { return false }
func (self *WantAuthorizerAdmission) Validate() error { return nil } func (self *WantAuthorizerAdmission) ValidateInitialization() error { return nil }
var _ admission.Interface = &WantAuthorizerAdmission{} var _ admission.Interface = &WantAuthorizerAdmission{}
var _ initializer.WantsAuthorizer = &WantAuthorizerAdmission{} var _ initializer.WantsAuthorizer = &WantAuthorizerAdmission{}
...@@ -145,7 +145,7 @@ type clientCertWanter struct { ...@@ -145,7 +145,7 @@ type clientCertWanter struct {
func (s *clientCertWanter) SetClientCert(cert, key []byte) { s.gotCert, s.gotKey = cert, key } func (s *clientCertWanter) SetClientCert(cert, key []byte) { s.gotCert, s.gotKey = cert, key }
func (s *clientCertWanter) Admit(a admission.Attributes) error { return nil } func (s *clientCertWanter) Admit(a admission.Attributes) error { return nil }
func (s *clientCertWanter) Handles(o admission.Operation) bool { return false } func (s *clientCertWanter) Handles(o admission.Operation) bool { return false }
func (s *clientCertWanter) Validate() error { return nil } func (s *clientCertWanter) ValidateInitialization() error { return nil }
// WantSchemeAdmission is a test stub that fulfills the WantsScheme interface. // WantSchemeAdmission is a test stub that fulfills the WantsScheme interface.
type WantSchemeAdmission struct { type WantSchemeAdmission struct {
...@@ -155,7 +155,7 @@ type WantSchemeAdmission struct { ...@@ -155,7 +155,7 @@ type WantSchemeAdmission struct {
func (self *WantSchemeAdmission) SetScheme(s *runtime.Scheme) { self.scheme = s } func (self *WantSchemeAdmission) SetScheme(s *runtime.Scheme) { self.scheme = s }
func (self *WantSchemeAdmission) Admit(a admission.Attributes) error { return nil } func (self *WantSchemeAdmission) Admit(a admission.Attributes) error { return nil }
func (self *WantSchemeAdmission) Handles(o admission.Operation) bool { return false } func (self *WantSchemeAdmission) Handles(o admission.Operation) bool { return false }
func (self *WantSchemeAdmission) Validate() error { return nil } func (self *WantSchemeAdmission) ValidateInitialization() error { return nil }
var _ admission.Interface = &WantSchemeAdmission{} var _ admission.Interface = &WantSchemeAdmission{}
var _ initializer.WantsScheme = &WantSchemeAdmission{} var _ initializer.WantsScheme = &WantSchemeAdmission{}
...@@ -27,23 +27,23 @@ import ( ...@@ -27,23 +27,23 @@ import (
// WantsExternalKubeClientSet defines a function which sets external ClientSet for admission plugins that need it // WantsExternalKubeClientSet defines a function which sets external ClientSet for admission plugins that need it
type WantsExternalKubeClientSet interface { type WantsExternalKubeClientSet interface {
SetExternalKubeClientSet(kubernetes.Interface) SetExternalKubeClientSet(kubernetes.Interface)
admission.Validator admission.InitializationValidator
} }
// WantsExternalKubeInformerFactory defines a function which sets InformerFactory for admission plugins that need it // WantsExternalKubeInformerFactory defines a function which sets InformerFactory for admission plugins that need it
type WantsExternalKubeInformerFactory interface { type WantsExternalKubeInformerFactory interface {
SetExternalKubeInformerFactory(informers.SharedInformerFactory) SetExternalKubeInformerFactory(informers.SharedInformerFactory)
admission.Validator admission.InitializationValidator
} }
// WantsAuthorizer defines a function which sets Authorizer for admission plugins that need it. // WantsAuthorizer defines a function which sets Authorizer for admission plugins that need it.
type WantsAuthorizer interface { type WantsAuthorizer interface {
SetAuthorizer(authorizer.Authorizer) SetAuthorizer(authorizer.Authorizer)
admission.Validator admission.InitializationValidator
} }
// WantsScheme defines a function that accepts runtime.Scheme for admission plugins that need it. // WantsScheme defines a function that accepts runtime.Scheme for admission plugins that need it.
type WantsScheme interface { type WantsScheme interface {
SetScheme(*runtime.Scheme) SetScheme(*runtime.Scheme)
admission.Validator admission.InitializationValidator
} }
...@@ -53,14 +53,26 @@ type Attributes interface { ...@@ -53,14 +53,26 @@ type Attributes interface {
// Interface is an abstract, pluggable interface for Admission Control decisions. // Interface is an abstract, pluggable interface for Admission Control decisions.
type Interface interface { type Interface interface {
// Admit makes an admission decision based on the request attributes
Admit(a Attributes) (err error)
// Handles returns true if this admission controller can handle the given operation // Handles returns true if this admission controller can handle the given operation
// where operation can be one of CREATE, UPDATE, DELETE, or CONNECT // where operation can be one of CREATE, UPDATE, DELETE, or CONNECT
Handles(operation Operation) bool Handles(operation Operation) bool
} }
type MutationInterface interface {
Interface
// Admit makes an admission decision based on the request attributes
Admit(a Attributes) (err error)
}
// ValidationInterface is an abstract, pluggable interface for Admission Control decisions.
type ValidationInterface interface {
Interface
// Validate makes an admission decision based on the request attributes. It is NOT allowed to mutate
Validate(a Attributes) (err error)
}
// Operation is the type of resource operation being checked for admission control // Operation is the type of resource operation being checked for admission control
type Operation string type Operation string
...@@ -78,10 +90,10 @@ type PluginInitializer interface { ...@@ -78,10 +90,10 @@ type PluginInitializer interface {
Initialize(plugin Interface) Initialize(plugin Interface)
} }
// Validator holds Validate functions, which are responsible for validation of initialized shared resources // InitializationValidator holds ValidateInitialization functions, which are responsible for validation of initialized
// and should be implemented on admission plugins // shared resources and should be implemented on admission plugins
type Validator interface { type InitializationValidator interface {
Validate() error ValidateInitialization() error
} }
// ConfigProvider provides a way to get configuration for an admission plugin based on its name // ConfigProvider provides a way to get configuration for an admission plugin based on its name
......
...@@ -74,8 +74,8 @@ func NewInitializer() admission.Interface { ...@@ -74,8 +74,8 @@ func NewInitializer() admission.Interface {
return &initializer{} return &initializer{}
} }
// Validate implements the Validator interface. // ValidateInitialization implements the InitializationValidator interface.
func (i *initializer) Validate() error { func (i *initializer) ValidateInitialization() error {
if i.config == nil { if i.config == nil {
return fmt.Errorf("the Initializer admission plugin requires a Kubernetes client to be provided") return fmt.Errorf("the Initializer admission plugin requires a Kubernetes client to be provided")
} }
......
...@@ -57,9 +57,9 @@ func Register(plugins *admission.Plugins) { ...@@ -57,9 +57,9 @@ func Register(plugins *admission.Plugins) {
}) })
} }
// lifecycle is an implementation of admission.Interface. // Lifecycle is an implementation of admission.Interface.
// It enforces life-cycle constraints around a Namespace depending on its Phase // It enforces life-cycle constraints around a Namespace depending on its Phase
type lifecycle struct { type Lifecycle struct {
*admission.Handler *admission.Handler
client kubernetes.Interface client kubernetes.Interface
immortalNamespaces sets.String immortalNamespaces sets.String
...@@ -73,8 +73,8 @@ type forceLiveLookupEntry struct { ...@@ -73,8 +73,8 @@ type forceLiveLookupEntry struct {
expiry time.Time expiry time.Time
} }
var _ = initializer.WantsExternalKubeInformerFactory(&lifecycle{}) var _ = initializer.WantsExternalKubeInformerFactory(&Lifecycle{})
var _ = initializer.WantsExternalKubeClientSet(&lifecycle{}) var _ = initializer.WantsExternalKubeClientSet(&Lifecycle{})
func makeNamespaceKey(namespace string) *v1.Namespace { func makeNamespaceKey(namespace string) *v1.Namespace {
return &v1.Namespace{ return &v1.Namespace{
...@@ -85,7 +85,7 @@ func makeNamespaceKey(namespace string) *v1.Namespace { ...@@ -85,7 +85,7 @@ func makeNamespaceKey(namespace string) *v1.Namespace {
} }
} }
func (l *lifecycle) Admit(a admission.Attributes) error { func (l *Lifecycle) Admit(a admission.Attributes) error {
// prevent deletion of immortal namespaces // prevent deletion of immortal namespaces
if a.GetOperation() == admission.Delete && a.GetKind().GroupKind() == v1.SchemeGroupVersion.WithKind("Namespace").GroupKind() && l.immortalNamespaces.Has(a.GetName()) { if a.GetOperation() == admission.Delete && a.GetKind().GroupKind() == v1.SchemeGroupVersion.WithKind("Namespace").GroupKind() && l.immortalNamespaces.Has(a.GetName()) {
return errors.NewForbidden(a.GetResource().GroupResource(), a.GetName(), fmt.Errorf("this namespace may not be deleted")) return errors.NewForbidden(a.GetResource().GroupResource(), a.GetName(), fmt.Errorf("this namespace may not be deleted"))
...@@ -188,14 +188,14 @@ func (l *lifecycle) Admit(a admission.Attributes) error { ...@@ -188,14 +188,14 @@ func (l *lifecycle) Admit(a admission.Attributes) error {
return nil return nil
} }
// NewLifecycle creates a new namespace lifecycle admission control handler // NewLifecycle creates a new namespace Lifecycle admission control handler
func NewLifecycle(immortalNamespaces sets.String) (admission.Interface, error) { func NewLifecycle(immortalNamespaces sets.String) (*Lifecycle, error) {
return newLifecycleWithClock(immortalNamespaces, clock.RealClock{}) return newLifecycleWithClock(immortalNamespaces, clock.RealClock{})
} }
func newLifecycleWithClock(immortalNamespaces sets.String, clock utilcache.Clock) (admission.Interface, error) { func newLifecycleWithClock(immortalNamespaces sets.String, clock utilcache.Clock) (*Lifecycle, error) {
forceLiveLookupCache := utilcache.NewLRUExpireCacheWithClock(100, clock) forceLiveLookupCache := utilcache.NewLRUExpireCacheWithClock(100, clock)
return &lifecycle{ return &Lifecycle{
Handler: admission.NewHandler(admission.Create, admission.Update, admission.Delete), Handler: admission.NewHandler(admission.Create, admission.Update, admission.Delete),
immortalNamespaces: immortalNamespaces, immortalNamespaces: immortalNamespaces,
forceLiveLookupCache: forceLiveLookupCache, forceLiveLookupCache: forceLiveLookupCache,
...@@ -203,19 +203,19 @@ func newLifecycleWithClock(immortalNamespaces sets.String, clock utilcache.Clock ...@@ -203,19 +203,19 @@ func newLifecycleWithClock(immortalNamespaces sets.String, clock utilcache.Clock
} }
// SetExternalKubeInformerFactory implements the WantsExternalKubeInformerFactory interface. // SetExternalKubeInformerFactory implements the WantsExternalKubeInformerFactory interface.
func (l *lifecycle) SetExternalKubeInformerFactory(f informers.SharedInformerFactory) { func (l *Lifecycle) SetExternalKubeInformerFactory(f informers.SharedInformerFactory) {
namespaceInformer := f.Core().V1().Namespaces() namespaceInformer := f.Core().V1().Namespaces()
l.namespaceLister = namespaceInformer.Lister() l.namespaceLister = namespaceInformer.Lister()
l.SetReadyFunc(namespaceInformer.Informer().HasSynced) l.SetReadyFunc(namespaceInformer.Informer().HasSynced)
} }
// SetExternalKubeClientSet implements the WantsExternalKubeClientSet interface. // SetExternalKubeClientSet implements the WantsExternalKubeClientSet interface.
func (l *lifecycle) SetExternalKubeClientSet(client kubernetes.Interface) { func (l *Lifecycle) SetExternalKubeClientSet(client kubernetes.Interface) {
l.client = client l.client = client
} }
// Validate implement the Validator interface. // ValidateInitialization implements the InitializationValidator interface.
func (l *lifecycle) Validate() error { func (l *Lifecycle) ValidateInitialization() error {
if l.namespaceLister == nil { if l.namespaceLister == nil {
return fmt.Errorf("missing namespaceLister") return fmt.Errorf("missing namespaceLister")
} }
......
...@@ -37,12 +37,12 @@ import ( ...@@ -37,12 +37,12 @@ import (
) )
// newHandlerForTest returns a configured handler for testing. // newHandlerForTest returns a configured handler for testing.
func newHandlerForTest(c clientset.Interface) (admission.Interface, informers.SharedInformerFactory, error) { func newHandlerForTest(c clientset.Interface) (*Lifecycle, informers.SharedInformerFactory, error) {
return newHandlerForTestWithClock(c, clock.RealClock{}) return newHandlerForTestWithClock(c, clock.RealClock{})
} }
// newHandlerForTestWithClock returns a configured handler for testing. // newHandlerForTestWithClock returns a configured handler for testing.
func newHandlerForTestWithClock(c clientset.Interface, cacheClock clock.Clock) (admission.Interface, informers.SharedInformerFactory, error) { func newHandlerForTestWithClock(c clientset.Interface, cacheClock clock.Clock) (*Lifecycle, informers.SharedInformerFactory, error) {
f := informers.NewSharedInformerFactory(c, 5*time.Minute) f := informers.NewSharedInformerFactory(c, 5*time.Minute)
handler, err := newLifecycleWithClock(sets.NewString(metav1.NamespaceDefault, metav1.NamespaceSystem), cacheClock) handler, err := newLifecycleWithClock(sets.NewString(metav1.NamespaceDefault, metav1.NamespaceSystem), cacheClock)
if err != nil { if err != nil {
...@@ -53,7 +53,7 @@ func newHandlerForTestWithClock(c clientset.Interface, cacheClock clock.Clock) ( ...@@ -53,7 +53,7 @@ func newHandlerForTestWithClock(c clientset.Interface, cacheClock clock.Clock) (
return handler, f, err return handler, f, err
} }
pluginInitializer.Initialize(handler) pluginInitializer.Initialize(handler)
err = admission.Validate(handler) err = admission.ValidateInitialization(handler)
return handler, f, err return handler, f, err
} }
......
...@@ -156,9 +156,8 @@ func (a *GenericAdmissionWebhook) SetExternalKubeClientSet(client clientset.Inte ...@@ -156,9 +156,8 @@ func (a *GenericAdmissionWebhook) SetExternalKubeClientSet(client clientset.Inte
a.hookSource = configuration.NewExternalAdmissionHookConfigurationManager(client.Admissionregistration().ExternalAdmissionHookConfigurations()) a.hookSource = configuration.NewExternalAdmissionHookConfigurationManager(client.Admissionregistration().ExternalAdmissionHookConfigurations())
} }
// Validator holds Validate functions, which are responsible for validation of initialized shared resources // ValidateInitialization implements the InitializationValidator interface.
// and should be implemented on admission plugins func (a *GenericAdmissionWebhook) ValidateInitialization() error {
func (a *GenericAdmissionWebhook) Validate() error {
if a.hookSource == nil { if a.hookSource == nil {
return fmt.Errorf("the GenericAdmissionWebhook admission plugin requires a Kubernetes client to be provided") return fmt.Errorf("the GenericAdmissionWebhook admission plugin requires a Kubernetes client to be provided")
} }
......
...@@ -156,18 +156,18 @@ func (ps *Plugins) InitPlugin(name string, config io.Reader, pluginInitializer P ...@@ -156,18 +156,18 @@ func (ps *Plugins) InitPlugin(name string, config io.Reader, pluginInitializer P
pluginInitializer.Initialize(plugin) pluginInitializer.Initialize(plugin)
// ensure that plugins have been properly initialized // ensure that plugins have been properly initialized
if err := Validate(plugin); err != nil { if err := ValidateInitialization(plugin); err != nil {
return nil, err return nil, err
} }
return plugin, nil return plugin, nil
} }
// Validate will call the Validate function in each plugin if they implement // ValidateInitialization will call the InitializationValidate function in each plugin if they implement
// the Validator interface. // the InitializationValidator interface.
func Validate(plugin Interface) error { func ValidateInitialization(plugin Interface) error {
if validater, ok := plugin.(Validator); ok { if validater, ok := plugin.(InitializationValidator); ok {
err := validater.Validate() err := validater.ValidateInitialization()
if err != nil { if err != nil {
return err return err
} }
......
...@@ -519,7 +519,7 @@ func (storage *SimpleRESTStorage) NewList() runtime.Object { ...@@ -519,7 +519,7 @@ func (storage *SimpleRESTStorage) NewList() runtime.Object {
return &genericapitesting.SimpleList{} return &genericapitesting.SimpleList{}
} }
func (storage *SimpleRESTStorage) Create(ctx request.Context, obj runtime.Object, includeUninitialized bool) (runtime.Object, error) { func (storage *SimpleRESTStorage) Create(ctx request.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, includeUninitialized bool) (runtime.Object, error) {
storage.checkContext(ctx) storage.checkContext(ctx)
storage.created = obj.(*genericapitesting.Simple) storage.created = obj.(*genericapitesting.Simple)
if err := storage.errors["create"]; err != nil { if err := storage.errors["create"]; err != nil {
...@@ -532,7 +532,7 @@ func (storage *SimpleRESTStorage) Create(ctx request.Context, obj runtime.Object ...@@ -532,7 +532,7 @@ func (storage *SimpleRESTStorage) Create(ctx request.Context, obj runtime.Object
return obj, err return obj, err
} }
func (storage *SimpleRESTStorage) Update(ctx request.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { func (storage *SimpleRESTStorage) Update(ctx request.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
storage.checkContext(ctx) storage.checkContext(ctx)
obj, err := objInfo.UpdatedObject(ctx, &storage.item) obj, err := objInfo.UpdatedObject(ctx, &storage.item)
if err != nil { if err != nil {
...@@ -714,7 +714,7 @@ type NamedCreaterRESTStorage struct { ...@@ -714,7 +714,7 @@ type NamedCreaterRESTStorage struct {
createdName string createdName string
} }
func (storage *NamedCreaterRESTStorage) Create(ctx request.Context, name string, obj runtime.Object, includeUninitialized bool) (runtime.Object, error) { func (storage *NamedCreaterRESTStorage) Create(ctx request.Context, name string, obj runtime.Object, createValidation rest.ValidateObjectFunc, includeUninitialized bool) (runtime.Object, error) {
storage.checkContext(ctx) storage.checkContext(ctx)
storage.created = obj.(*genericapitesting.Simple) storage.created = obj.(*genericapitesting.Simple)
storage.createdName = name storage.createdName = name
......
...@@ -93,10 +93,10 @@ func createHandler(r rest.NamedCreater, scope RequestScope, typer runtime.Object ...@@ -93,10 +93,10 @@ func createHandler(r rest.NamedCreater, scope RequestScope, typer runtime.Object
ae := request.AuditEventFrom(ctx) ae := request.AuditEventFrom(ctx)
audit.LogRequestObject(ae, obj, scope.Resource, scope.Subresource, scope.Serializer) audit.LogRequestObject(ae, obj, scope.Resource, scope.Subresource, scope.Serializer)
if admit != nil && admit.Handles(admission.Create) {
userInfo, _ := request.UserFrom(ctx) userInfo, _ := request.UserFrom(ctx)
admissionAttributes := admission.NewAttributesRecord(obj, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, userInfo)
err = admit.Admit(admission.NewAttributesRecord(obj, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, userInfo)) if mutatingAdmission, ok := admit.(admission.MutationInterface); ok && mutatingAdmission.Handles(admission.Create) {
err = mutatingAdmission.Admit(admissionAttributes)
if err != nil { if err != nil {
scope.err(err, w, req) scope.err(err, w, req)
return return
...@@ -108,7 +108,13 @@ func createHandler(r rest.NamedCreater, scope RequestScope, typer runtime.Object ...@@ -108,7 +108,13 @@ func createHandler(r rest.NamedCreater, scope RequestScope, typer runtime.Object
trace.Step("About to store object in database") trace.Step("About to store object in database")
result, err := finishRequest(timeout, func() (runtime.Object, error) { result, err := finishRequest(timeout, func() (runtime.Object, error) {
return r.Create(ctx, name, obj, includeUninitialized) return r.Create(
ctx,
name,
obj,
rest.AdmissionToValidateObjectFunc(admit, admissionAttributes),
includeUninitialized,
)
}) })
if err != nil { if err != nil {
scope.err(err, w, req) scope.err(err, w, req)
...@@ -144,19 +150,19 @@ func createHandler(r rest.NamedCreater, scope RequestScope, typer runtime.Object ...@@ -144,19 +150,19 @@ func createHandler(r rest.NamedCreater, scope RequestScope, typer runtime.Object
} }
// CreateNamedResource returns a function that will handle a resource creation with name. // CreateNamedResource returns a function that will handle a resource creation with name.
func CreateNamedResource(r rest.NamedCreater, scope RequestScope, typer runtime.ObjectTyper, admit admission.Interface) http.HandlerFunc { func CreateNamedResource(r rest.NamedCreater, scope RequestScope, typer runtime.ObjectTyper, admission admission.Interface) http.HandlerFunc {
return createHandler(r, scope, typer, admit, true) return createHandler(r, scope, typer, admission, true)
} }
// CreateResource returns a function that will handle a resource creation. // CreateResource returns a function that will handle a resource creation.
func CreateResource(r rest.Creater, scope RequestScope, typer runtime.ObjectTyper, admit admission.Interface) http.HandlerFunc { func CreateResource(r rest.Creater, scope RequestScope, typer runtime.ObjectTyper, admission admission.Interface) http.HandlerFunc {
return createHandler(&namedCreaterAdapter{r}, scope, typer, admit, false) return createHandler(&namedCreaterAdapter{r}, scope, typer, admission, false)
} }
type namedCreaterAdapter struct { type namedCreaterAdapter struct {
rest.Creater rest.Creater
} }
func (c *namedCreaterAdapter) Create(ctx request.Context, name string, obj runtime.Object, includeUninitialized bool) (runtime.Object, error) { func (c *namedCreaterAdapter) Create(ctx request.Context, name string, obj runtime.Object, createValidatingAdmission rest.ValidateObjectFunc, includeUninitialized bool) (runtime.Object, error) {
return c.Creater.Create(ctx, obj, includeUninitialized) return c.Creater.Create(ctx, obj, createValidatingAdmission, includeUninitialized)
} }
...@@ -34,6 +34,7 @@ import ( ...@@ -34,6 +34,7 @@ import (
) )
// DeleteResource returns a function that will handle a resource deletion // DeleteResource returns a function that will handle a resource deletion
// TODO admission here becomes solely validating admission
func DeleteResource(r rest.GracefulDeleter, allowsOptions bool, scope RequestScope, admit admission.Interface) http.HandlerFunc { func DeleteResource(r rest.GracefulDeleter, allowsOptions bool, scope RequestScope, admit admission.Interface) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) { return func(w http.ResponseWriter, req *http.Request) {
// For performance tracking purposes. // For performance tracking purposes.
...@@ -95,13 +96,20 @@ func DeleteResource(r rest.GracefulDeleter, allowsOptions bool, scope RequestSco ...@@ -95,13 +96,20 @@ func DeleteResource(r rest.GracefulDeleter, allowsOptions bool, scope RequestSco
trace.Step("About to check admission control") trace.Step("About to check admission control")
if admit != nil && admit.Handles(admission.Delete) { if admit != nil && admit.Handles(admission.Delete) {
userInfo, _ := request.UserFrom(ctx) userInfo, _ := request.UserFrom(ctx)
attrs := admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Delete, userInfo)
err = admit.Admit(admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Delete, userInfo)) if mutatingAdmission, ok := admit.(admission.MutationInterface); ok {
if err != nil { if err := mutatingAdmission.Admit(attrs); err != nil {
scope.err(err, w, req)
return
}
}
if validatingAdmission, ok := admit.(admission.ValidationInterface); ok {
if err := validatingAdmission.Validate(attrs); err != nil {
scope.err(err, w, req) scope.err(err, w, req)
return return
} }
} }
}
trace.Step("About to delete object from database") trace.Step("About to delete object from database")
wasDeleted := true wasDeleted := true
...@@ -171,10 +179,20 @@ func DeleteCollection(r rest.CollectionDeleter, checkBody bool, scope RequestSco ...@@ -171,10 +179,20 @@ func DeleteCollection(r rest.CollectionDeleter, checkBody bool, scope RequestSco
ctx := scope.ContextFunc(req) ctx := scope.ContextFunc(req)
ctx = request.WithNamespace(ctx, namespace) ctx = request.WithNamespace(ctx, namespace)
if admit != nil && admit.Handles(admission.Delete) { if mutatingAdmission, ok := admit.(admission.MutationInterface); ok && mutatingAdmission.Handles(admission.Delete) {
userInfo, _ := request.UserFrom(ctx)
err = mutatingAdmission.Admit(admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, "", scope.Resource, scope.Subresource, admission.Delete, userInfo))
if err != nil {
scope.err(err, w, req)
return
}
}
// TODO: avoid calling Handles twice
if validatingAdmission, ok := admit.(admission.ValidationInterface); ok && validatingAdmission.Handles(admission.Delete) {
userInfo, _ := request.UserFrom(ctx) userInfo, _ := request.UserFrom(ctx)
err = admit.Admit(admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, "", scope.Resource, scope.Subresource, admission.Delete, userInfo)) err = validatingAdmission.Validate(admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, "", scope.Resource, scope.Subresource, admission.Delete, userInfo))
if err != nil { if err != nil {
scope.err(err, w, req) scope.err(err, w, req)
return return
......
...@@ -92,16 +92,25 @@ func PatchResource(r rest.Patcher, scope RequestScope, admit admission.Interface ...@@ -92,16 +92,25 @@ func PatchResource(r rest.Patcher, scope RequestScope, admit admission.Interface
scope.Serializer.DecoderToVersion(s.Serializer, schema.GroupVersion{Group: gv.Group, Version: runtime.APIVersionInternal}), scope.Serializer.DecoderToVersion(s.Serializer, schema.GroupVersion{Group: gv.Group, Version: runtime.APIVersionInternal}),
) )
updateAdmit := func(updatedObject runtime.Object, currentObject runtime.Object) error {
if admit != nil && admit.Handles(admission.Update) {
userInfo, _ := request.UserFrom(ctx) userInfo, _ := request.UserFrom(ctx)
return admit.Admit(admission.NewAttributesRecord(updatedObject, currentObject, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, userInfo)) staticAdmissionAttributes := admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, userInfo)
updateMutation := func(updatedObject runtime.Object, currentObject runtime.Object) error {
if mutatingAdmission, ok := admit.(admission.MutationInterface); ok && admit.Handles(admission.Update) {
return mutatingAdmission.Admit(admission.NewAttributesRecord(updatedObject, currentObject, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, userInfo))
} }
return nil return nil
} }
result, err := patchResource(ctx, updateAdmit, timeout, versionedObj, r, name, patchType, patchJS, result, err := patchResource(
ctx,
updateMutation,
rest.AdmissionToValidateObjectFunc(admit, staticAdmissionAttributes),
rest.AdmissionToValidateObjectUpdateFunc(admit, staticAdmissionAttributes),
timeout, versionedObj,
r,
name,
patchType,
patchJS,
scope.Namer, scope.Creater, scope.Defaulter, scope.UnsafeConvertor, scope.Kind, scope.Resource, codec) scope.Namer, scope.Creater, scope.Defaulter, scope.UnsafeConvertor, scope.Kind, scope.Resource, codec)
if err != nil { if err != nil {
scope.err(err, w, req) scope.err(err, w, req)
...@@ -122,12 +131,14 @@ func PatchResource(r rest.Patcher, scope RequestScope, admit admission.Interface ...@@ -122,12 +131,14 @@ func PatchResource(r rest.Patcher, scope RequestScope, admit admission.Interface
} }
} }
type updateAdmissionFunc func(updatedObject runtime.Object, currentObject runtime.Object) error type mutateObjectUpdateFunc func(obj, old runtime.Object) error
// patchResource divides PatchResource for easier unit testing // patchResource divides PatchResource for easier unit testing
func patchResource( func patchResource(
ctx request.Context, ctx request.Context,
admit updateAdmissionFunc, updateMutation mutateObjectUpdateFunc,
createValidation rest.ValidateObjectFunc,
updateValidation rest.ValidateObjectUpdateFunc,
timeout time.Duration, timeout time.Duration,
versionedObj runtime.Object, versionedObj runtime.Object,
patcher rest.Patcher, patcher rest.Patcher,
...@@ -341,16 +352,15 @@ func patchResource( ...@@ -341,16 +352,15 @@ func patchResource(
// applyAdmission is called every time GuaranteedUpdate asks for the updated object, // applyAdmission is called every time GuaranteedUpdate asks for the updated object,
// and is given the currently persisted object and the patched object as input. // and is given the currently persisted object and the patched object as input.
applyAdmission := func(ctx request.Context, patchedObject runtime.Object, currentObject runtime.Object) (runtime.Object, error) { applyAdmission := func(ctx request.Context, patchedObject runtime.Object, currentObject runtime.Object) (runtime.Object, error) {
return patchedObject, admit(patchedObject, currentObject) return patchedObject, updateMutation(patchedObject, currentObject)
} }
updatedObjectInfo := rest.DefaultUpdatedObjectInfo(nil, applyPatch, applyAdmission) updatedObjectInfo := rest.DefaultUpdatedObjectInfo(nil, applyPatch, applyAdmission)
return finishRequest(timeout, func() (runtime.Object, error) { return finishRequest(timeout, func() (runtime.Object, error) {
updateObject, _, updateErr := patcher.Update(ctx, name, updatedObjectInfo) updateObject, _, updateErr := patcher.Update(ctx, name, updatedObjectInfo, createValidation, updateValidation)
for i := 0; i < MaxRetryWhenPatchConflicts && (errors.IsConflict(updateErr)); i++ { for i := 0; i < MaxRetryWhenPatchConflicts && (errors.IsConflict(updateErr)); i++ {
lastConflictErr = updateErr lastConflictErr = updateErr
updateObject, _, updateErr = patcher.Update(ctx, name, updatedObjectInfo) updateObject, _, updateErr = patcher.Update(ctx, name, updatedObjectInfo, createValidation, updateValidation)
} }
return updateObject, updateErr return updateObject, updateErr
}) })
......
...@@ -117,13 +117,22 @@ func ConnectResource(connecter rest.Connecter, scope RequestScope, admit admissi ...@@ -117,13 +117,22 @@ func ConnectResource(connecter rest.Connecter, scope RequestScope, admit admissi
ResourcePath: restPath, ResourcePath: restPath,
} }
userInfo, _ := request.UserFrom(ctx) userInfo, _ := request.UserFrom(ctx)
// TODO: remove the mutating admission here as soon as we have ported all plugin that handle CONNECT
err = admit.Admit(admission.NewAttributesRecord(connectRequest, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Connect, userInfo)) if mutatingAdmit, ok := admit.(admission.MutationInterface); ok {
err = mutatingAdmit.Admit(admission.NewAttributesRecord(connectRequest, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Connect, userInfo))
if err != nil { if err != nil {
scope.err(err, w, req) scope.err(err, w, req)
return return
} }
} }
if mutatingAdmit, ok := admit.(admission.ValidationInterface); ok {
err = mutatingAdmit.Validate(admission.NewAttributesRecord(connectRequest, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Connect, userInfo))
if err != nil {
scope.err(err, w, req)
return
}
}
}
requestInfo, _ := request.RequestInfoFrom(ctx) requestInfo, _ := request.RequestInfoFrom(ctx)
metrics.RecordLongRunning(req, requestInfo, func() { metrics.RecordLongRunning(req, requestInfo, func() {
handler, err := connecter.Connect(ctx, name, opts, &responder{scope: scope, req: req, w: w}) handler, err := connecter.Connect(ctx, name, opts, &responder{scope: scope, req: req, w: w})
......
...@@ -170,7 +170,7 @@ func (p *testPatcher) New() runtime.Object { ...@@ -170,7 +170,7 @@ func (p *testPatcher) New() runtime.Object {
return &example.Pod{} return &example.Pod{}
} }
func (p *testPatcher) Update(ctx request.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { func (p *testPatcher) Update(ctx request.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
currentPod := p.startingPod currentPod := p.startingPod
if p.numUpdates > 0 { if p.numUpdates > 0 {
currentPod = p.updatePod currentPod = p.updatePod
...@@ -235,7 +235,8 @@ type patchTestCase struct { ...@@ -235,7 +235,8 @@ type patchTestCase struct {
name string name string
// admission chain to use, nil is fine // admission chain to use, nil is fine
admit updateAdmissionFunc admissionMutation mutateObjectUpdateFunc
admissionValidation rest.ValidateObjectUpdateFunc // TODO: add test for this
// startingPod is used as the starting point for the first Update // startingPod is used as the starting point for the first Update
startingPod *example.Pod startingPod *example.Pod
...@@ -257,9 +258,16 @@ func (tc *patchTestCase) Run(t *testing.T) { ...@@ -257,9 +258,16 @@ func (tc *patchTestCase) Run(t *testing.T) {
name := tc.startingPod.Name name := tc.startingPod.Name
codec := codecs.LegacyCodec(examplev1.SchemeGroupVersion) codec := codecs.LegacyCodec(examplev1.SchemeGroupVersion)
admit := tc.admit
if admit == nil { admissionMutation := tc.admissionMutation
admit = func(updatedObject runtime.Object, currentObject runtime.Object) error { if admissionMutation == nil {
admissionMutation = func(updatedObject runtime.Object, currentObject runtime.Object) error {
return nil
}
}
admissionValidation := tc.admissionValidation
if admissionValidation == nil {
admissionValidation = func(updatedObject runtime.Object, currentObject runtime.Object) error {
return nil return nil
} }
} }
...@@ -321,7 +329,18 @@ func (tc *patchTestCase) Run(t *testing.T) { ...@@ -321,7 +329,18 @@ func (tc *patchTestCase) Run(t *testing.T) {
} }
resultObj, err := patchResource(ctx, admit, 1*time.Second, versionedObj, testPatcher, name, patchType, patch, namer, creater, defaulter, convertor, kind, resource, codec) resultObj, err := patchResource(
ctx,
admissionMutation,
rest.ValidateAllObjectFunc,
admissionValidation,
1*time.Second,
versionedObj,
testPatcher,
name,
patchType,
patch,
namer, creater, defaulter, convertor, kind, resource, codec)
if len(tc.expectedError) != 0 { if len(tc.expectedError) != 0 {
if err == nil || err.Error() != tc.expectedError { if err == nil || err.Error() != tc.expectedError {
t.Errorf("%s: expected error %v, but got %v", tc.name, tc.expectedError, err) t.Errorf("%s: expected error %v, but got %v", tc.name, tc.expectedError, err)
...@@ -544,7 +563,7 @@ func TestPatchWithAdmissionRejection(t *testing.T) { ...@@ -544,7 +563,7 @@ func TestPatchWithAdmissionRejection(t *testing.T) {
tc := &patchTestCase{ tc := &patchTestCase{
name: "TestPatchWithAdmissionRejection", name: "TestPatchWithAdmissionRejection",
admit: func(updatedObject runtime.Object, currentObject runtime.Object) error { admissionMutation: func(updatedObject runtime.Object, currentObject runtime.Object) error {
return errors.New("admission failure") return errors.New("admission failure")
}, },
...@@ -583,7 +602,7 @@ func TestPatchWithVersionConflictThenAdmissionFailure(t *testing.T) { ...@@ -583,7 +602,7 @@ func TestPatchWithVersionConflictThenAdmissionFailure(t *testing.T) {
tc := &patchTestCase{ tc := &patchTestCase{
name: "TestPatchWithVersionConflictThenAdmissionFailure", name: "TestPatchWithVersionConflictThenAdmissionFailure",
admit: func(updatedObject runtime.Object, currentObject runtime.Object) error { admissionMutation: func(updatedObject runtime.Object, currentObject runtime.Object) error {
if seen { if seen {
return errors.New("admission failure") return errors.New("admission failure")
} }
......
...@@ -86,18 +86,25 @@ func UpdateResource(r rest.Updater, scope RequestScope, typer runtime.ObjectType ...@@ -86,18 +86,25 @@ func UpdateResource(r rest.Updater, scope RequestScope, typer runtime.ObjectType
return return
} }
userInfo, _ := request.UserFrom(ctx)
staticAdmissionAttributes := admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, userInfo)
var transformers []rest.TransformFunc var transformers []rest.TransformFunc
if admit != nil && admit.Handles(admission.Update) { if mutatingAdmission, ok := admit.(admission.MutationInterface); ok && mutatingAdmission.Handles(admission.Update) {
transformers = append(transformers, func(ctx request.Context, newObj, oldObj runtime.Object) (runtime.Object, error) { transformers = append(transformers, func(ctx request.Context, newObj, oldObj runtime.Object) (runtime.Object, error) {
userInfo, _ := request.UserFrom(ctx) return newObj, mutatingAdmission.Admit(admission.NewAttributesRecord(newObj, oldObj, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, userInfo))
return newObj, admit.Admit(admission.NewAttributesRecord(newObj, oldObj, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, userInfo))
}) })
} }
trace.Step("About to store object in database") trace.Step("About to store object in database")
wasCreated := false wasCreated := false
result, err := finishRequest(timeout, func() (runtime.Object, error) { result, err := finishRequest(timeout, func() (runtime.Object, error) {
obj, created, err := r.Update(ctx, name, rest.DefaultUpdatedObjectInfo(obj, transformers...)) obj, created, err := r.Update(
ctx,
name,
rest.DefaultUpdatedObjectInfo(obj, transformers...),
rest.AdmissionToValidateObjectFunc(admit, staticAdmissionAttributes),
rest.AdmissionToValidateObjectUpdateFunc(admit, staticAdmissionAttributes),
)
wasCreated = created wasCreated = created
return obj, err return obj, err
}) })
......
...@@ -148,11 +148,13 @@ type Store struct { ...@@ -148,11 +148,13 @@ type Store struct {
// AfterCreate implements a further operation to run after a resource is // AfterCreate implements a further operation to run after a resource is
// created and before it is decorated, optional. // created and before it is decorated, optional.
AfterCreate ObjectFunc AfterCreate ObjectFunc
// UpdateStrategy implements resource-specific behavior during updates. // UpdateStrategy implements resource-specific behavior during updates.
UpdateStrategy rest.RESTUpdateStrategy UpdateStrategy rest.RESTUpdateStrategy
// AfterUpdate implements a further operation to run after a resource is // AfterUpdate implements a further operation to run after a resource is
// updated and before it is decorated, optional. // updated and before it is decorated, optional.
AfterUpdate ObjectFunc AfterUpdate ObjectFunc
// DeleteStrategy implements resource-specific behavior during deletion. // DeleteStrategy implements resource-specific behavior during deletion.
DeleteStrategy rest.RESTDeleteStrategy DeleteStrategy rest.RESTDeleteStrategy
// AfterDelete implements a further operation to run after a resource is // AfterDelete implements a further operation to run after a resource is
...@@ -303,10 +305,18 @@ func (e *Store) ListPredicate(ctx genericapirequest.Context, p storage.Selection ...@@ -303,10 +305,18 @@ func (e *Store) ListPredicate(ctx genericapirequest.Context, p storage.Selection
} }
// Create inserts a new item according to the unique key from the object. // Create inserts a new item according to the unique key from the object.
func (e *Store) Create(ctx genericapirequest.Context, obj runtime.Object, includeUninitialized bool) (runtime.Object, error) { func (e *Store) Create(ctx genericapirequest.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, includeUninitialized bool) (runtime.Object, error) {
if err := rest.BeforeCreate(e.CreateStrategy, ctx, obj); err != nil { if err := rest.BeforeCreate(e.CreateStrategy, ctx, obj); err != nil {
return nil, err return nil, err
} }
// at this point we have a fully formed object. It is time to call the validators that the apiserver
// handling chain wants to enforce.
if createValidation != nil {
if err := createValidation(obj.DeepCopyObject()); err != nil {
return nil, err
}
}
name, err := e.ObjectNameFunc(obj) name, err := e.ObjectNameFunc(obj)
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -494,7 +504,7 @@ func (e *Store) deleteWithoutFinalizers(ctx genericapirequest.Context, name, key ...@@ -494,7 +504,7 @@ func (e *Store) deleteWithoutFinalizers(ctx genericapirequest.Context, name, key
// Update performs an atomic update and set of the object. Returns the result of the update // Update performs an atomic update and set of the object. Returns the result of the update
// or an error. If the registry allows create-on-update, the create flow will be executed. // or an error. If the registry allows create-on-update, the create flow will be executed.
// A bool is returned along with the object and any errors, to indicate object creation. // A bool is returned along with the object and any errors, to indicate object creation.
func (e *Store) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { func (e *Store) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
key, err := e.KeyFunc(ctx, name) key, err := e.KeyFunc(ctx, name)
if err != nil { if err != nil {
return nil, false, err return nil, false, err
...@@ -544,10 +554,18 @@ func (e *Store) Update(ctx genericapirequest.Context, name string, objInfo rest. ...@@ -544,10 +554,18 @@ func (e *Store) Update(ctx genericapirequest.Context, name string, objInfo rest.
if err := rest.BeforeCreate(e.CreateStrategy, ctx, obj); err != nil { if err := rest.BeforeCreate(e.CreateStrategy, ctx, obj); err != nil {
return nil, nil, err return nil, nil, err
} }
// at this point we have a fully formed object. It is time to call the validators that the apiserver
// handling chain wants to enforce.
if createValidation != nil {
if err := createValidation(obj.DeepCopyObject()); err != nil {
return nil, nil, err
}
}
ttl, err := e.calculateTTL(obj, 0, false) ttl, err := e.calculateTTL(obj, 0, false)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
return obj, &ttl, nil return obj, &ttl, nil
} }
...@@ -582,6 +600,13 @@ func (e *Store) Update(ctx genericapirequest.Context, name string, objInfo rest. ...@@ -582,6 +600,13 @@ func (e *Store) Update(ctx genericapirequest.Context, name string, objInfo rest.
if err := rest.BeforeUpdate(e.UpdateStrategy, ctx, obj, existing); err != nil { if err := rest.BeforeUpdate(e.UpdateStrategy, ctx, obj, existing); err != nil {
return nil, nil, err return nil, nil, err
} }
// at this point we have a fully formed object. It is time to call the validators that the apiserver
// handling chain wants to enforce.
if updateValidation != nil {
if err := updateValidation(obj.DeepCopyObject(), existing.DeepCopyObject()); err != nil {
return nil, nil, err
}
}
if e.shouldDeleteDuringUpdate(ctx, key, obj, existing) { if e.shouldDeleteDuringUpdate(ctx, key, obj, existing) {
deleteObj = obj deleteObj = obj
return nil, nil, errEmptiedFinalizers return nil, nil, errEmptiedFinalizers
......
...@@ -245,7 +245,7 @@ func TestStoreListResourceVersion(t *testing.T) { ...@@ -245,7 +245,7 @@ func TestStoreListResourceVersion(t *testing.T) {
destroyFunc, registry := newTestGenericStoreRegistry(t, scheme, true) destroyFunc, registry := newTestGenericStoreRegistry(t, scheme, true)
defer destroyFunc() defer destroyFunc()
obj, err := registry.Create(ctx, fooPod, false) obj, err := registry.Create(ctx, fooPod, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -275,7 +275,7 @@ func TestStoreListResourceVersion(t *testing.T) { ...@@ -275,7 +275,7 @@ func TestStoreListResourceVersion(t *testing.T) {
t.Fatalf("expected waiting, but get %#v", l) t.Fatalf("expected waiting, but get %#v", l)
} }
if _, err := registry.Create(ctx, barPod, false); err != nil { if _, err := registry.Create(ctx, barPod, rest.ValidateAllObjectFunc, false); err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -312,7 +312,7 @@ func TestStoreCreate(t *testing.T) { ...@@ -312,7 +312,7 @@ func TestStoreCreate(t *testing.T) {
registry.DeleteStrategy = testGracefulStrategy{defaultDeleteStrategy} registry.DeleteStrategy = testGracefulStrategy{defaultDeleteStrategy}
// create the object // create the object
objA, err := registry.Create(testContext, podA, false) objA, err := registry.Create(testContext, podA, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
...@@ -329,7 +329,7 @@ func TestStoreCreate(t *testing.T) { ...@@ -329,7 +329,7 @@ func TestStoreCreate(t *testing.T) {
} }
// now try to create the second pod // now try to create the second pod
_, err = registry.Create(testContext, podB, false) _, err = registry.Create(testContext, podB, rest.ValidateAllObjectFunc, false)
if !errors.IsAlreadyExists(err) { if !errors.IsAlreadyExists(err) {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
...@@ -348,7 +348,7 @@ func TestStoreCreate(t *testing.T) { ...@@ -348,7 +348,7 @@ func TestStoreCreate(t *testing.T) {
} }
// try to create before graceful deletion period is over // try to create before graceful deletion period is over
_, err = registry.Create(testContext, podA, false) _, err = registry.Create(testContext, podA, rest.ValidateAllObjectFunc, false)
if err == nil || !errors.IsAlreadyExists(err) { if err == nil || !errors.IsAlreadyExists(err) {
t.Fatalf("Expected 'already exists' error from storage, but got %v", err) t.Fatalf("Expected 'already exists' error from storage, but got %v", err)
} }
...@@ -440,7 +440,7 @@ func TestStoreCreateInitialized(t *testing.T) { ...@@ -440,7 +440,7 @@ func TestStoreCreateInitialized(t *testing.T) {
} }
pod.Initializers = nil pod.Initializers = nil
updated, _, err := registry.Update(ctx, podA.Name, rest.DefaultUpdatedObjectInfo(pod)) updated, _, err := registry.Update(ctx, podA.Name, rest.DefaultUpdatedObjectInfo(pod), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -476,7 +476,7 @@ func TestStoreCreateInitialized(t *testing.T) { ...@@ -476,7 +476,7 @@ func TestStoreCreateInitialized(t *testing.T) {
}() }()
// create the object // create the object
objA, err := registry.Create(ctx, podA, false) objA, err := registry.Create(ctx, podA, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
...@@ -533,7 +533,7 @@ func TestStoreCreateInitializedFailed(t *testing.T) { ...@@ -533,7 +533,7 @@ func TestStoreCreateInitializedFailed(t *testing.T) {
} }
pod.Initializers.Pending = nil pod.Initializers.Pending = nil
pod.Initializers.Result = &metav1.Status{Status: metav1.StatusFailure, Code: 403, Reason: metav1.StatusReasonForbidden, Message: "induced failure"} pod.Initializers.Result = &metav1.Status{Status: metav1.StatusFailure, Code: 403, Reason: metav1.StatusReasonForbidden, Message: "induced failure"}
updated, _, err := registry.Update(ctx, podA.Name, rest.DefaultUpdatedObjectInfo(pod)) updated, _, err := registry.Update(ctx, podA.Name, rest.DefaultUpdatedObjectInfo(pod), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -556,7 +556,7 @@ func TestStoreCreateInitializedFailed(t *testing.T) { ...@@ -556,7 +556,7 @@ func TestStoreCreateInitializedFailed(t *testing.T) {
}() }()
// create the object // create the object
_, err := registry.Create(ctx, podA, false) _, err := registry.Create(ctx, podA, rest.ValidateAllObjectFunc, false)
if !errors.IsForbidden(err) { if !errors.IsForbidden(err) {
t.Fatalf("unexpected error: %#v", err.(errors.APIStatus).Status()) t.Fatalf("unexpected error: %#v", err.(errors.APIStatus).Status())
} }
...@@ -574,7 +574,7 @@ func TestStoreCreateInitializedFailed(t *testing.T) { ...@@ -574,7 +574,7 @@ func TestStoreCreateInitializedFailed(t *testing.T) {
} }
func updateAndVerify(t *testing.T, ctx genericapirequest.Context, registry *Store, pod *example.Pod) bool { func updateAndVerify(t *testing.T, ctx genericapirequest.Context, registry *Store, pod *example.Pod) bool {
obj, _, err := registry.Update(ctx, pod.Name, rest.DefaultUpdatedObjectInfo(pod)) obj, _, err := registry.Update(ctx, pod.Name, rest.DefaultUpdatedObjectInfo(pod), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if err != nil { if err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
return false return false
...@@ -610,7 +610,7 @@ func TestStoreUpdate(t *testing.T) { ...@@ -610,7 +610,7 @@ func TestStoreUpdate(t *testing.T) {
defer destroyFunc() defer destroyFunc()
// Test1 try to update a non-existing node // Test1 try to update a non-existing node
_, _, err := registry.Update(testContext, podA.Name, rest.DefaultUpdatedObjectInfo(podA)) _, _, err := registry.Update(testContext, podA.Name, rest.DefaultUpdatedObjectInfo(podA), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if !errors.IsNotFound(err) { if !errors.IsNotFound(err) {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
...@@ -623,7 +623,7 @@ func TestStoreUpdate(t *testing.T) { ...@@ -623,7 +623,7 @@ func TestStoreUpdate(t *testing.T) {
registry.UpdateStrategy.(*testRESTStrategy).allowCreateOnUpdate = false registry.UpdateStrategy.(*testRESTStrategy).allowCreateOnUpdate = false
// Test3 outofDate // Test3 outofDate
_, _, err = registry.Update(testContext, podAWithResourceVersion.Name, rest.DefaultUpdatedObjectInfo(podAWithResourceVersion)) _, _, err = registry.Update(testContext, podAWithResourceVersion.Name, rest.DefaultUpdatedObjectInfo(podAWithResourceVersion), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if !errors.IsConflict(err) { if !errors.IsConflict(err) {
t.Errorf("Unexpected error updating podAWithResourceVersion: %v", err) t.Errorf("Unexpected error updating podAWithResourceVersion: %v", err)
} }
...@@ -660,7 +660,7 @@ func TestNoOpUpdates(t *testing.T) { ...@@ -660,7 +660,7 @@ func TestNoOpUpdates(t *testing.T) {
var err error var err error
var createResult runtime.Object var createResult runtime.Object
if createResult, err = registry.Create(genericapirequest.NewDefaultContext(), newPod(), false); err != nil { if createResult, err = registry.Create(genericapirequest.NewDefaultContext(), newPod(), rest.ValidateAllObjectFunc, false); err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
...@@ -671,7 +671,7 @@ func TestNoOpUpdates(t *testing.T) { ...@@ -671,7 +671,7 @@ func TestNoOpUpdates(t *testing.T) {
var updateResult runtime.Object var updateResult runtime.Object
p := newPod() p := newPod()
if updateResult, _, err = registry.Update(genericapirequest.NewDefaultContext(), p.Name, rest.DefaultUpdatedObjectInfo(p)); err != nil { if updateResult, _, err = registry.Update(genericapirequest.NewDefaultContext(), p.Name, rest.DefaultUpdatedObjectInfo(p), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc); err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
...@@ -835,7 +835,7 @@ func TestStoreDelete(t *testing.T) { ...@@ -835,7 +835,7 @@ func TestStoreDelete(t *testing.T) {
} }
// create pod // create pod
_, err = registry.Create(testContext, podA, false) _, err = registry.Create(testContext, podA, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
...@@ -873,7 +873,7 @@ func TestStoreDeleteUninitialized(t *testing.T) { ...@@ -873,7 +873,7 @@ func TestStoreDeleteUninitialized(t *testing.T) {
} }
// create pod // create pod
_, err = registry.Create(testContext, podA, true) _, err = registry.Create(testContext, podA, rest.ValidateAllObjectFunc, true)
if err != nil { if err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
...@@ -950,7 +950,7 @@ func TestGracefulStoreHandleFinalizers(t *testing.T) { ...@@ -950,7 +950,7 @@ func TestGracefulStoreHandleFinalizers(t *testing.T) {
registry.EnableGarbageCollection = gcEnabled registry.EnableGarbageCollection = gcEnabled
// create pod // create pod
_, err := registry.Create(testContext, podWithFinalizer, false) _, err := registry.Create(testContext, podWithFinalizer, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
...@@ -972,7 +972,7 @@ func TestGracefulStoreHandleFinalizers(t *testing.T) { ...@@ -972,7 +972,7 @@ func TestGracefulStoreHandleFinalizers(t *testing.T) {
ObjectMeta: metav1.ObjectMeta{Name: "foo", Finalizers: []string{"foo.com/x"}, ResourceVersion: podWithFinalizer.ObjectMeta.ResourceVersion}, ObjectMeta: metav1.ObjectMeta{Name: "foo", Finalizers: []string{"foo.com/x"}, ResourceVersion: podWithFinalizer.ObjectMeta.ResourceVersion},
Spec: example.PodSpec{NodeName: "machine"}, Spec: example.PodSpec{NodeName: "machine"},
} }
_, _, err = registry.Update(testContext, updatedPodWithFinalizer.ObjectMeta.Name, rest.DefaultUpdatedObjectInfo(updatedPodWithFinalizer)) _, _, err = registry.Update(testContext, updatedPodWithFinalizer.ObjectMeta.Name, rest.DefaultUpdatedObjectInfo(updatedPodWithFinalizer), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if err != nil { if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
...@@ -987,7 +987,7 @@ func TestGracefulStoreHandleFinalizers(t *testing.T) { ...@@ -987,7 +987,7 @@ func TestGracefulStoreHandleFinalizers(t *testing.T) {
ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: podWithFinalizer.ObjectMeta.ResourceVersion}, ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: podWithFinalizer.ObjectMeta.ResourceVersion},
Spec: example.PodSpec{NodeName: "anothermachine"}, Spec: example.PodSpec{NodeName: "anothermachine"},
} }
_, _, err = registry.Update(testContext, podWithFinalizer.ObjectMeta.Name, rest.DefaultUpdatedObjectInfo(podWithNoFinalizer)) _, _, err = registry.Update(testContext, podWithFinalizer.ObjectMeta.Name, rest.DefaultUpdatedObjectInfo(podWithNoFinalizer), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if err != nil { if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
...@@ -1016,7 +1016,7 @@ func TestFailedInitializationStoreUpdate(t *testing.T) { ...@@ -1016,7 +1016,7 @@ func TestFailedInitializationStoreUpdate(t *testing.T) {
defer destroyFunc() defer destroyFunc()
// create pod, view initializing // create pod, view initializing
obj, err := registry.Create(testContext, podInitializing, true) obj, err := registry.Create(testContext, podInitializing, rest.ValidateAllObjectFunc, true)
if err != nil { if err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
...@@ -1024,7 +1024,7 @@ func TestFailedInitializationStoreUpdate(t *testing.T) { ...@@ -1024,7 +1024,7 @@ func TestFailedInitializationStoreUpdate(t *testing.T) {
// update the pod with initialization failure, the pod should be deleted // update the pod with initialization failure, the pod should be deleted
pod.Initializers.Result = &metav1.Status{Status: metav1.StatusFailure} pod.Initializers.Result = &metav1.Status{Status: metav1.StatusFailure}
result, _, err := registry.Update(testContext, podInitializing.Name, rest.DefaultUpdatedObjectInfo(pod)) result, _, err := registry.Update(testContext, podInitializing.Name, rest.DefaultUpdatedObjectInfo(pod), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if err != nil { if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
...@@ -1055,7 +1055,7 @@ func TestNonGracefulStoreHandleFinalizers(t *testing.T) { ...@@ -1055,7 +1055,7 @@ func TestNonGracefulStoreHandleFinalizers(t *testing.T) {
registry.EnableGarbageCollection = gcEnabled registry.EnableGarbageCollection = gcEnabled
// create pod // create pod
_, err := registry.Create(testContext, podWithFinalizer, false) _, err := registry.Create(testContext, podWithFinalizer, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
...@@ -1092,7 +1092,7 @@ func TestNonGracefulStoreHandleFinalizers(t *testing.T) { ...@@ -1092,7 +1092,7 @@ func TestNonGracefulStoreHandleFinalizers(t *testing.T) {
ObjectMeta: metav1.ObjectMeta{Name: "foo", Finalizers: []string{"foo.com/x"}, ResourceVersion: podWithFinalizer.ObjectMeta.ResourceVersion}, ObjectMeta: metav1.ObjectMeta{Name: "foo", Finalizers: []string{"foo.com/x"}, ResourceVersion: podWithFinalizer.ObjectMeta.ResourceVersion},
Spec: example.PodSpec{NodeName: "machine"}, Spec: example.PodSpec{NodeName: "machine"},
} }
_, _, err = registry.Update(testContext, updatedPodWithFinalizer.ObjectMeta.Name, rest.DefaultUpdatedObjectInfo(updatedPodWithFinalizer)) _, _, err = registry.Update(testContext, updatedPodWithFinalizer.ObjectMeta.Name, rest.DefaultUpdatedObjectInfo(updatedPodWithFinalizer), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if err != nil { if err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
...@@ -1111,7 +1111,7 @@ func TestNonGracefulStoreHandleFinalizers(t *testing.T) { ...@@ -1111,7 +1111,7 @@ func TestNonGracefulStoreHandleFinalizers(t *testing.T) {
ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: podWithFinalizer.ObjectMeta.ResourceVersion}, ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: podWithFinalizer.ObjectMeta.ResourceVersion},
Spec: example.PodSpec{NodeName: "anothermachine"}, Spec: example.PodSpec{NodeName: "anothermachine"},
} }
_, _, err = registry.Update(testContext, podWithFinalizer.ObjectMeta.Name, rest.DefaultUpdatedObjectInfo(podWithNoFinalizer)) _, _, err = registry.Update(testContext, podWithFinalizer.ObjectMeta.Name, rest.DefaultUpdatedObjectInfo(podWithNoFinalizer), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if err != nil { if err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
...@@ -1357,7 +1357,7 @@ func TestStoreDeleteWithOrphanDependents(t *testing.T) { ...@@ -1357,7 +1357,7 @@ func TestStoreDeleteWithOrphanDependents(t *testing.T) {
for _, tc := range testcases { for _, tc := range testcases {
registry.DeleteStrategy = tc.strategy registry.DeleteStrategy = tc.strategy
// create pod // create pod
_, err := registry.Create(testContext, tc.pod, false) _, err := registry.Create(testContext, tc.pod, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
...@@ -1576,7 +1576,7 @@ func TestStoreDeletionPropagation(t *testing.T) { ...@@ -1576,7 +1576,7 @@ func TestStoreDeletionPropagation(t *testing.T) {
i++ i++
pod := createPod(i, tc.existingFinalizers) pod := createPod(i, tc.existingFinalizers)
// create pod // create pod
_, err := registry.Create(testContext, pod, false) _, err := registry.Create(testContext, pod, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
...@@ -1628,13 +1628,13 @@ func TestStoreDeleteCollection(t *testing.T) { ...@@ -1628,13 +1628,13 @@ func TestStoreDeleteCollection(t *testing.T) {
destroyFunc, registry := NewTestGenericStoreRegistry(t) destroyFunc, registry := NewTestGenericStoreRegistry(t)
defer destroyFunc() defer destroyFunc()
if _, err := registry.Create(testContext, podA, false); err != nil { if _, err := registry.Create(testContext, podA, rest.ValidateAllObjectFunc, false); err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
if _, err := registry.Create(testContext, podB, false); err != nil { if _, err := registry.Create(testContext, podB, rest.ValidateAllObjectFunc, false); err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
if _, err := registry.Create(testContext, podC, true); err != nil { if _, err := registry.Create(testContext, podC, rest.ValidateAllObjectFunc, true); err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
...@@ -1670,10 +1670,10 @@ func TestStoreDeleteCollectionNotFound(t *testing.T) { ...@@ -1670,10 +1670,10 @@ func TestStoreDeleteCollectionNotFound(t *testing.T) {
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
// Setup // Setup
if _, err := registry.Create(testContext, podA, false); err != nil { if _, err := registry.Create(testContext, podA, rest.ValidateAllObjectFunc, false); err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
if _, err := registry.Create(testContext, podB, false); err != nil { if _, err := registry.Create(testContext, podB, rest.ValidateAllObjectFunc, false); err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
...@@ -1709,7 +1709,7 @@ func TestStoreDeleteCollectionWithWatch(t *testing.T) { ...@@ -1709,7 +1709,7 @@ func TestStoreDeleteCollectionWithWatch(t *testing.T) {
destroyFunc, registry := NewTestGenericStoreRegistry(t) destroyFunc, registry := NewTestGenericStoreRegistry(t)
defer destroyFunc() defer destroyFunc()
objCreated, err := registry.Create(testContext, podA, false) objCreated, err := registry.Create(testContext, podA, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
...@@ -1778,7 +1778,7 @@ func TestStoreWatch(t *testing.T) { ...@@ -1778,7 +1778,7 @@ func TestStoreWatch(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("%v: unexpected error: %v", name, err) t.Errorf("%v: unexpected error: %v", name, err)
} else { } else {
obj, err := registry.Create(testContext, podA, false) obj, err := registry.Create(testContext, podA, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
got, open := <-wi.ResultChan() got, open := <-wi.ResultChan()
if !open { if !open {
...@@ -1922,7 +1922,7 @@ func TestQualifiedResource(t *testing.T) { ...@@ -1922,7 +1922,7 @@ func TestQualifiedResource(t *testing.T) {
defer destroyFunc() defer destroyFunc()
// update a non-exist object // update a non-exist object
_, _, err := registry.Update(testContext, podA.Name, rest.DefaultUpdatedObjectInfo(podA)) _, _, err := registry.Update(testContext, podA.Name, rest.DefaultUpdatedObjectInfo(podA), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if !errors.IsNotFound(err) { if !errors.IsNotFound(err) {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
...@@ -1954,13 +1954,13 @@ func TestQualifiedResource(t *testing.T) { ...@@ -1954,13 +1954,13 @@ func TestQualifiedResource(t *testing.T) {
} }
// create a non-exist object // create a non-exist object
_, err = registry.Create(testContext, podA, false) _, err = registry.Create(testContext, podA, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
// create a exist object will fail // create a exist object will fail
_, err = registry.Create(testContext, podA, false) _, err = registry.Create(testContext, podA, rest.ValidateAllObjectFunc, false)
if !errors.IsAlreadyExists(err) { if !errors.IsAlreadyExists(err) {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
......
...@@ -49,6 +49,7 @@ go_library( ...@@ -49,6 +49,7 @@ go_library(
"//vendor/k8s.io/apimachinery/pkg/util/uuid:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/uuid:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library", "//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
"//vendor/k8s.io/apiserver/pkg/admission:go_default_library",
"//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library", "//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library",
"//vendor/k8s.io/apiserver/pkg/features:go_default_library", "//vendor/k8s.io/apiserver/pkg/features:go_default_library",
"//vendor/k8s.io/apiserver/pkg/storage/names:go_default_library", "//vendor/k8s.io/apiserver/pkg/storage/names:go_default_library",
......
...@@ -25,6 +25,7 @@ import ( ...@@ -25,6 +25,7 @@ import (
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/apiserver/pkg/admission"
genericapirequest "k8s.io/apiserver/pkg/endpoints/request" genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/features" "k8s.io/apiserver/pkg/features"
"k8s.io/apiserver/pkg/storage/names" "k8s.io/apiserver/pkg/storage/names"
...@@ -151,3 +152,28 @@ type NamespaceScopedStrategy interface { ...@@ -151,3 +152,28 @@ type NamespaceScopedStrategy interface {
// NamespaceScoped returns if the object must be in a namespace. // NamespaceScoped returns if the object must be in a namespace.
NamespaceScoped() bool NamespaceScoped() bool
} }
// AdmissionToValidateObjectFunc converts validating admission to a rest validate object func
func AdmissionToValidateObjectFunc(admit admission.Interface, staticAttributes admission.Attributes) ValidateObjectFunc {
validatingAdmission, ok := admit.(admission.ValidationInterface)
if !ok {
return func(obj runtime.Object) error { return nil }
}
return func(obj runtime.Object) error {
finalAttributes := admission.NewAttributesRecord(
obj,
staticAttributes.GetOldObject(),
staticAttributes.GetKind(),
staticAttributes.GetNamespace(),
staticAttributes.GetName(),
staticAttributes.GetResource(),
staticAttributes.GetSubresource(),
staticAttributes.GetOperation(),
staticAttributes.GetUserInfo(),
)
if !validatingAdmission.Handles(finalAttributes.GetOperation()) {
return nil
}
return validatingAdmission.Validate(finalAttributes)
}
}
...@@ -192,7 +192,7 @@ type Creater interface { ...@@ -192,7 +192,7 @@ type Creater interface {
// Create creates a new version of a resource. If includeUninitialized is set, the object may be returned // Create creates a new version of a resource. If includeUninitialized is set, the object may be returned
// without completing initialization. // without completing initialization.
Create(ctx genericapirequest.Context, obj runtime.Object, includeUninitialized bool) (runtime.Object, error) Create(ctx genericapirequest.Context, obj runtime.Object, createValidation ValidateObjectFunc, includeUninitialized bool) (runtime.Object, error)
} }
// NamedCreater is an object that can create an instance of a RESTful object using a name parameter. // NamedCreater is an object that can create an instance of a RESTful object using a name parameter.
...@@ -205,7 +205,7 @@ type NamedCreater interface { ...@@ -205,7 +205,7 @@ type NamedCreater interface {
// This is needed for create operations on subresources which include the name of the parent // This is needed for create operations on subresources which include the name of the parent
// resource in the path. If includeUninitialized is set, the object may be returned without // resource in the path. If includeUninitialized is set, the object may be returned without
// completing initialization. // completing initialization.
Create(ctx genericapirequest.Context, name string, obj runtime.Object, includeUninitialized bool) (runtime.Object, error) Create(ctx genericapirequest.Context, name string, obj runtime.Object, createValidation ValidateObjectFunc, includeUninitialized bool) (runtime.Object, error)
} }
// UpdatedObjectInfo provides information about an updated object to an Updater. // UpdatedObjectInfo provides information about an updated object to an Updater.
...@@ -221,6 +221,26 @@ type UpdatedObjectInfo interface { ...@@ -221,6 +221,26 @@ type UpdatedObjectInfo interface {
UpdatedObject(ctx genericapirequest.Context, oldObj runtime.Object) (newObj runtime.Object, err error) UpdatedObject(ctx genericapirequest.Context, oldObj runtime.Object) (newObj runtime.Object, err error)
} }
// ValidateObjectFunc is a function to act on a given object. An error may be returned
// if the hook cannot be completed. An ObjectFunc may NOT transform the provided
// object.
type ValidateObjectFunc func(obj runtime.Object) error
// ValidateAllObjectFunc is a "admit everything" instance of ValidateObjectFunc.
func ValidateAllObjectFunc(obj runtime.Object) error {
return nil
}
// ValidateObjectUpdateFunc is a function to act on a given object and its predecessor.
// An error may be returned if the hook cannot be completed. An UpdateObjectFunc
// may NOT transform the provided object.
type ValidateObjectUpdateFunc func(obj, old runtime.Object) error
// ValidateAllObjectUpdateFunc is a "admit everything" instance of ValidateObjectUpdateFunc.
func ValidateAllObjectUpdateFunc(obj, old runtime.Object) error {
return nil
}
// Updater is an object that can update an instance of a RESTful object. // Updater is an object that can update an instance of a RESTful object.
type Updater interface { type Updater interface {
// New returns an empty object that can be used with Update after request data has been put into it. // New returns an empty object that can be used with Update after request data has been put into it.
...@@ -230,14 +250,14 @@ type Updater interface { ...@@ -230,14 +250,14 @@ type Updater interface {
// Update finds a resource in the storage and updates it. Some implementations // Update finds a resource in the storage and updates it. Some implementations
// may allow updates creates the object - they should set the created boolean // may allow updates creates the object - they should set the created boolean
// to true. // to true.
Update(ctx genericapirequest.Context, name string, objInfo UpdatedObjectInfo) (runtime.Object, bool, error) Update(ctx genericapirequest.Context, name string, objInfo UpdatedObjectInfo, createValidation ValidateObjectFunc, updateValidation ValidateObjectUpdateFunc) (runtime.Object, bool, error)
} }
// CreaterUpdater is a storage object that must support both create and update. // CreaterUpdater is a storage object that must support both create and update.
// Go prevents embedded interfaces that implement the same method. // Go prevents embedded interfaces that implement the same method.
type CreaterUpdater interface { type CreaterUpdater interface {
Creater Creater
Update(ctx genericapirequest.Context, name string, objInfo UpdatedObjectInfo) (runtime.Object, bool, error) Update(ctx genericapirequest.Context, name string, objInfo UpdatedObjectInfo, createValidation ValidateObjectFunc, updateValidation ValidateObjectUpdateFunc) (runtime.Object, bool, error)
} }
// CreaterUpdater must satisfy the Updater interface. // CreaterUpdater must satisfy the Updater interface.
......
...@@ -244,7 +244,7 @@ func (t *Tester) testCreateAlreadyExisting(obj runtime.Object, createFn CreateFu ...@@ -244,7 +244,7 @@ func (t *Tester) testCreateAlreadyExisting(obj runtime.Object, createFn CreateFu
} }
defer t.delete(ctx, foo) defer t.delete(ctx, foo)
_, err := t.storage.(rest.Creater).Create(ctx, foo, false) _, err := t.storage.(rest.Creater).Create(ctx, foo, rest.ValidateAllObjectFunc, false)
if !errors.IsAlreadyExists(err) { if !errors.IsAlreadyExists(err) {
t.Errorf("expected already exists err, got %v", err) t.Errorf("expected already exists err, got %v", err)
} }
...@@ -256,7 +256,7 @@ func (t *Tester) testCreateEquals(obj runtime.Object, getFn GetFunc) { ...@@ -256,7 +256,7 @@ func (t *Tester) testCreateEquals(obj runtime.Object, getFn GetFunc) {
foo := obj.DeepCopyObject() foo := obj.DeepCopyObject()
t.setObjectMeta(foo, t.namer(2)) t.setObjectMeta(foo, t.namer(2))
created, err := t.storage.(rest.Creater).Create(ctx, foo, false) created, err := t.storage.(rest.Creater).Create(ctx, foo, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
...@@ -284,7 +284,7 @@ func (t *Tester) testCreateDiscardsObjectNamespace(valid runtime.Object) { ...@@ -284,7 +284,7 @@ func (t *Tester) testCreateDiscardsObjectNamespace(valid runtime.Object) {
objectMeta.SetNamespace("not-default") objectMeta.SetNamespace("not-default")
// Ideally, we'd get an error back here, but at least verify the namespace wasn't persisted // Ideally, we'd get an error back here, but at least verify the namespace wasn't persisted
created, err := t.storage.(rest.Creater).Create(t.TestContext(), valid.DeepCopyObject(), false) created, err := t.storage.(rest.Creater).Create(t.TestContext(), valid.DeepCopyObject(), rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
...@@ -300,7 +300,7 @@ func (t *Tester) testCreateGeneratesName(valid runtime.Object) { ...@@ -300,7 +300,7 @@ func (t *Tester) testCreateGeneratesName(valid runtime.Object) {
objectMeta.SetName("") objectMeta.SetName("")
objectMeta.SetGenerateName("test-") objectMeta.SetGenerateName("test-")
created, err := t.storage.(rest.Creater).Create(t.TestContext(), valid, false) created, err := t.storage.(rest.Creater).Create(t.TestContext(), valid, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
...@@ -315,7 +315,7 @@ func (t *Tester) testCreateHasMetadata(valid runtime.Object) { ...@@ -315,7 +315,7 @@ func (t *Tester) testCreateHasMetadata(valid runtime.Object) {
objectMeta.SetName(t.namer(1)) objectMeta.SetName(t.namer(1))
objectMeta.SetNamespace(t.TestNamespace()) objectMeta.SetNamespace(t.TestNamespace())
obj, err := t.storage.(rest.Creater).Create(t.TestContext(), valid, false) obj, err := t.storage.(rest.Creater).Create(t.TestContext(), valid, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
...@@ -333,7 +333,7 @@ func (t *Tester) testCreateIgnoresContextNamespace(valid runtime.Object) { ...@@ -333,7 +333,7 @@ func (t *Tester) testCreateIgnoresContextNamespace(valid runtime.Object) {
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), "not-default2") ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), "not-default2")
// Ideally, we'd get an error back here, but at least verify the namespace wasn't persisted // Ideally, we'd get an error back here, but at least verify the namespace wasn't persisted
created, err := t.storage.(rest.Creater).Create(ctx, valid.DeepCopyObject(), false) created, err := t.storage.(rest.Creater).Create(ctx, valid.DeepCopyObject(), rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
...@@ -352,7 +352,7 @@ func (t *Tester) testCreateIgnoresMismatchedNamespace(valid runtime.Object) { ...@@ -352,7 +352,7 @@ func (t *Tester) testCreateIgnoresMismatchedNamespace(valid runtime.Object) {
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), "not-default2") ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), "not-default2")
// Ideally, we'd get an error back here, but at least verify the namespace wasn't persisted // Ideally, we'd get an error back here, but at least verify the namespace wasn't persisted
created, err := t.storage.(rest.Creater).Create(ctx, valid.DeepCopyObject(), false) created, err := t.storage.(rest.Creater).Create(ctx, valid.DeepCopyObject(), rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
...@@ -370,7 +370,7 @@ func (t *Tester) testCreateValidatesNames(valid runtime.Object) { ...@@ -370,7 +370,7 @@ func (t *Tester) testCreateValidatesNames(valid runtime.Object) {
objCopyMeta.SetName(invalidName) objCopyMeta.SetName(invalidName)
ctx := t.TestContext() ctx := t.TestContext()
_, err := t.storage.(rest.Creater).Create(ctx, objCopy, false) _, err := t.storage.(rest.Creater).Create(ctx, objCopy, rest.ValidateAllObjectFunc, false)
if !errors.IsInvalid(err) { if !errors.IsInvalid(err) {
t.Errorf("%s: Expected to get an invalid resource error, got '%v'", invalidName, err) t.Errorf("%s: Expected to get an invalid resource error, got '%v'", invalidName, err)
} }
...@@ -382,7 +382,7 @@ func (t *Tester) testCreateValidatesNames(valid runtime.Object) { ...@@ -382,7 +382,7 @@ func (t *Tester) testCreateValidatesNames(valid runtime.Object) {
objCopyMeta.SetName(objCopyMeta.GetName() + invalidSuffix) objCopyMeta.SetName(objCopyMeta.GetName() + invalidSuffix)
ctx := t.TestContext() ctx := t.TestContext()
_, err := t.storage.(rest.Creater).Create(ctx, objCopy, false) _, err := t.storage.(rest.Creater).Create(ctx, objCopy, rest.ValidateAllObjectFunc, false)
if !errors.IsInvalid(err) { if !errors.IsInvalid(err) {
t.Errorf("%s: Expected to get an invalid resource error, got '%v'", invalidSuffix, err) t.Errorf("%s: Expected to get an invalid resource error, got '%v'", invalidSuffix, err)
} }
...@@ -392,7 +392,7 @@ func (t *Tester) testCreateValidatesNames(valid runtime.Object) { ...@@ -392,7 +392,7 @@ func (t *Tester) testCreateValidatesNames(valid runtime.Object) {
func (t *Tester) testCreateInvokesValidation(invalid ...runtime.Object) { func (t *Tester) testCreateInvokesValidation(invalid ...runtime.Object) {
for i, obj := range invalid { for i, obj := range invalid {
ctx := t.TestContext() ctx := t.TestContext()
_, err := t.storage.(rest.Creater).Create(ctx, obj, false) _, err := t.storage.(rest.Creater).Create(ctx, obj, rest.ValidateAllObjectFunc, false)
if !errors.IsInvalid(err) { if !errors.IsInvalid(err) {
t.Errorf("%d: Expected to get an invalid resource error, got %v", i, err) t.Errorf("%d: Expected to get an invalid resource error, got %v", i, err)
} }
...@@ -403,7 +403,7 @@ func (t *Tester) testCreateRejectsMismatchedNamespace(valid runtime.Object) { ...@@ -403,7 +403,7 @@ func (t *Tester) testCreateRejectsMismatchedNamespace(valid runtime.Object) {
objectMeta := t.getObjectMetaOrFail(valid) objectMeta := t.getObjectMetaOrFail(valid)
objectMeta.SetNamespace("not-default") objectMeta.SetNamespace("not-default")
_, err := t.storage.(rest.Creater).Create(t.TestContext(), valid, false) _, err := t.storage.(rest.Creater).Create(t.TestContext(), valid, rest.ValidateAllObjectFunc, false)
if err == nil { if err == nil {
t.Errorf("Expected an error, but we didn't get one") t.Errorf("Expected an error, but we didn't get one")
} else if !strings.Contains(err.Error(), "does not match the namespace sent on the request") { } else if !strings.Contains(err.Error(), "does not match the namespace sent on the request") {
...@@ -417,7 +417,7 @@ func (t *Tester) testCreateResetsUserData(valid runtime.Object) { ...@@ -417,7 +417,7 @@ func (t *Tester) testCreateResetsUserData(valid runtime.Object) {
objectMeta.SetUID("bad-uid") objectMeta.SetUID("bad-uid")
objectMeta.SetCreationTimestamp(now) objectMeta.SetCreationTimestamp(now)
obj, err := t.storage.(rest.Creater).Create(t.TestContext(), valid, false) obj, err := t.storage.(rest.Creater).Create(t.TestContext(), valid, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
...@@ -435,7 +435,7 @@ func (t *Tester) testCreateIgnoreClusterName(valid runtime.Object) { ...@@ -435,7 +435,7 @@ func (t *Tester) testCreateIgnoreClusterName(valid runtime.Object) {
objectMeta.SetName(t.namer(3)) objectMeta.SetName(t.namer(3))
objectMeta.SetClusterName("clustername-to-ignore") objectMeta.SetClusterName("clustername-to-ignore")
obj, err := t.storage.(rest.Creater).Create(t.TestContext(), valid.DeepCopyObject(), false) obj, err := t.storage.(rest.Creater).Create(t.TestContext(), valid.DeepCopyObject(), rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
...@@ -464,7 +464,7 @@ func (t *Tester) testUpdateEquals(obj runtime.Object, createFn CreateFunc, getFn ...@@ -464,7 +464,7 @@ func (t *Tester) testUpdateEquals(obj runtime.Object, createFn CreateFunc, getFn
} }
toUpdate = updateFn(toUpdate) toUpdate = updateFn(toUpdate)
toUpdateMeta := t.getObjectMetaOrFail(toUpdate) toUpdateMeta := t.getObjectMetaOrFail(toUpdate)
updated, created, err := t.storage.(rest.Updater).Update(ctx, toUpdateMeta.GetName(), rest.DefaultUpdatedObjectInfo(toUpdate)) updated, created, err := t.storage.(rest.Updater).Update(ctx, toUpdateMeta.GetName(), rest.DefaultUpdatedObjectInfo(toUpdate), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
...@@ -504,7 +504,7 @@ func (t *Tester) testUpdateFailsOnVersionTooOld(obj runtime.Object, createFn Cre ...@@ -504,7 +504,7 @@ func (t *Tester) testUpdateFailsOnVersionTooOld(obj runtime.Object, createFn Cre
olderMeta := t.getObjectMetaOrFail(older) olderMeta := t.getObjectMetaOrFail(older)
olderMeta.SetResourceVersion("1") olderMeta.SetResourceVersion("1")
_, _, err = t.storage.(rest.Updater).Update(t.TestContext(), olderMeta.GetName(), rest.DefaultUpdatedObjectInfo(older)) _, _, err = t.storage.(rest.Updater).Update(t.TestContext(), olderMeta.GetName(), rest.DefaultUpdatedObjectInfo(older), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if err == nil { if err == nil {
t.Errorf("Expected an error, but we didn't get one") t.Errorf("Expected an error, but we didn't get one")
} else if !errors.IsConflict(err) { } else if !errors.IsConflict(err) {
...@@ -524,7 +524,7 @@ func (t *Tester) testUpdateInvokesValidation(obj runtime.Object, createFn Create ...@@ -524,7 +524,7 @@ func (t *Tester) testUpdateInvokesValidation(obj runtime.Object, createFn Create
for _, update := range invalidUpdateFn { for _, update := range invalidUpdateFn {
toUpdate := update(foo.DeepCopyObject()) toUpdate := update(foo.DeepCopyObject())
toUpdateMeta := t.getObjectMetaOrFail(toUpdate) toUpdateMeta := t.getObjectMetaOrFail(toUpdate)
got, created, err := t.storage.(rest.Updater).Update(t.TestContext(), toUpdateMeta.GetName(), rest.DefaultUpdatedObjectInfo(toUpdate)) got, created, err := t.storage.(rest.Updater).Update(t.TestContext(), toUpdateMeta.GetName(), rest.DefaultUpdatedObjectInfo(toUpdate), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if got != nil || created { if got != nil || created {
t.Errorf("expected nil object and no creation for object: %v", toUpdate) t.Errorf("expected nil object and no creation for object: %v", toUpdate)
} }
...@@ -545,7 +545,7 @@ func (t *Tester) testUpdateWithWrongUID(obj runtime.Object, createFn CreateFunc, ...@@ -545,7 +545,7 @@ func (t *Tester) testUpdateWithWrongUID(obj runtime.Object, createFn CreateFunc,
} }
objectMeta.SetUID(types.UID("UID1111")) objectMeta.SetUID(types.UID("UID1111"))
obj, created, err := t.storage.(rest.Updater).Update(ctx, objectMeta.GetName(), rest.DefaultUpdatedObjectInfo(foo)) obj, created, err := t.storage.(rest.Updater).Update(ctx, objectMeta.GetName(), rest.DefaultUpdatedObjectInfo(foo), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if created || obj != nil { if created || obj != nil {
t.Errorf("expected nil object and no creation for object: %v", foo) t.Errorf("expected nil object and no creation for object: %v", foo)
} }
...@@ -589,7 +589,7 @@ func (t *Tester) testUpdateRetrievesOldObject(obj runtime.Object, createFn Creat ...@@ -589,7 +589,7 @@ func (t *Tester) testUpdateRetrievesOldObject(obj runtime.Object, createFn Creat
return updatedObject, nil return updatedObject, nil
} }
updatedObj, created, err := t.storage.(rest.Updater).Update(ctx, objectMeta.GetName(), rest.DefaultUpdatedObjectInfo(storedFooWithUpdates, noopTransform)) updatedObj, created, err := t.storage.(rest.Updater).Update(ctx, objectMeta.GetName(), rest.DefaultUpdatedObjectInfo(storedFooWithUpdates, noopTransform), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
return return
...@@ -624,7 +624,7 @@ func (t *Tester) testUpdatePropagatesUpdatedObjectError(obj runtime.Object, crea ...@@ -624,7 +624,7 @@ func (t *Tester) testUpdatePropagatesUpdatedObjectError(obj runtime.Object, crea
return nil, propagateErr return nil, propagateErr
} }
_, _, err := t.storage.(rest.Updater).Update(ctx, name, rest.DefaultUpdatedObjectInfo(foo, noopTransform)) _, _, err := t.storage.(rest.Updater).Update(ctx, name, rest.DefaultUpdatedObjectInfo(foo, noopTransform), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if err != propagateErr { if err != propagateErr {
t.Errorf("expected propagated error, got %#v", err) t.Errorf("expected propagated error, got %#v", err)
} }
...@@ -650,7 +650,7 @@ func (t *Tester) testUpdateIgnoreGenerationUpdates(obj runtime.Object, createFn ...@@ -650,7 +650,7 @@ func (t *Tester) testUpdateIgnoreGenerationUpdates(obj runtime.Object, createFn
olderMeta := t.getObjectMetaOrFail(older) olderMeta := t.getObjectMetaOrFail(older)
olderMeta.SetGeneration(2) olderMeta.SetGeneration(2)
_, _, err = t.storage.(rest.Updater).Update(t.TestContext(), olderMeta.GetName(), rest.DefaultUpdatedObjectInfo(older)) _, _, err = t.storage.(rest.Updater).Update(t.TestContext(), olderMeta.GetName(), rest.DefaultUpdatedObjectInfo(older), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if err != nil { if err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
...@@ -666,7 +666,7 @@ func (t *Tester) testUpdateIgnoreGenerationUpdates(obj runtime.Object, createFn ...@@ -666,7 +666,7 @@ func (t *Tester) testUpdateIgnoreGenerationUpdates(obj runtime.Object, createFn
func (t *Tester) testUpdateOnNotFound(obj runtime.Object) { func (t *Tester) testUpdateOnNotFound(obj runtime.Object) {
t.setObjectMeta(obj, t.namer(0)) t.setObjectMeta(obj, t.namer(0))
_, created, err := t.storage.(rest.Updater).Update(t.TestContext(), t.namer(0), rest.DefaultUpdatedObjectInfo(obj)) _, created, err := t.storage.(rest.Updater).Update(t.TestContext(), t.namer(0), rest.DefaultUpdatedObjectInfo(obj), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if t.createOnUpdate { if t.createOnUpdate {
if err != nil { if err != nil {
t.Errorf("creation allowed on updated, but got an error: %v", err) t.Errorf("creation allowed on updated, but got an error: %v", err)
...@@ -701,7 +701,7 @@ func (t *Tester) testUpdateRejectsMismatchedNamespace(obj runtime.Object, create ...@@ -701,7 +701,7 @@ func (t *Tester) testUpdateRejectsMismatchedNamespace(obj runtime.Object, create
objectMeta.SetName(t.namer(1)) objectMeta.SetName(t.namer(1))
objectMeta.SetNamespace("not-default") objectMeta.SetNamespace("not-default")
obj, updated, err := t.storage.(rest.Updater).Update(t.TestContext(), "foo1", rest.DefaultUpdatedObjectInfo(storedFoo)) obj, updated, err := t.storage.(rest.Updater).Update(t.TestContext(), "foo1", rest.DefaultUpdatedObjectInfo(storedFoo), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if obj != nil || updated { if obj != nil || updated {
t.Errorf("expected nil object and not updated") t.Errorf("expected nil object and not updated")
} }
...@@ -732,7 +732,7 @@ func (t *Tester) testUpdateIgnoreClusterName(obj runtime.Object, createFn Create ...@@ -732,7 +732,7 @@ func (t *Tester) testUpdateIgnoreClusterName(obj runtime.Object, createFn Create
olderMeta := t.getObjectMetaOrFail(older) olderMeta := t.getObjectMetaOrFail(older)
olderMeta.SetClusterName("clustername-to-ignore") olderMeta.SetClusterName("clustername-to-ignore")
_, _, err = t.storage.(rest.Updater).Update(t.TestContext(), olderMeta.GetName(), rest.DefaultUpdatedObjectInfo(older)) _, _, err = t.storage.(rest.Updater).Update(t.TestContext(), olderMeta.GetName(), rest.DefaultUpdatedObjectInfo(older), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc)
if err != nil { if err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
...@@ -1064,14 +1064,14 @@ func (t *Tester) testGetDifferentNamespace(obj runtime.Object) { ...@@ -1064,14 +1064,14 @@ func (t *Tester) testGetDifferentNamespace(obj runtime.Object) {
ctx1 := genericapirequest.WithNamespace(genericapirequest.NewContext(), "bar3") ctx1 := genericapirequest.WithNamespace(genericapirequest.NewContext(), "bar3")
objMeta.SetNamespace(genericapirequest.NamespaceValue(ctx1)) objMeta.SetNamespace(genericapirequest.NamespaceValue(ctx1))
_, err := t.storage.(rest.Creater).Create(ctx1, obj, false) _, err := t.storage.(rest.Creater).Create(ctx1, obj, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
ctx2 := genericapirequest.WithNamespace(genericapirequest.NewContext(), "bar4") ctx2 := genericapirequest.WithNamespace(genericapirequest.NewContext(), "bar4")
objMeta.SetNamespace(genericapirequest.NamespaceValue(ctx2)) objMeta.SetNamespace(genericapirequest.NamespaceValue(ctx2))
_, err = t.storage.(rest.Creater).Create(ctx2, obj, false) _, err = t.storage.(rest.Creater).Create(ctx2, obj, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
...@@ -1105,7 +1105,7 @@ func (t *Tester) testGetFound(obj runtime.Object) { ...@@ -1105,7 +1105,7 @@ func (t *Tester) testGetFound(obj runtime.Object) {
ctx := t.TestContext() ctx := t.TestContext()
t.setObjectMeta(obj, t.namer(1)) t.setObjectMeta(obj, t.namer(1))
existing, err := t.storage.(rest.Creater).Create(ctx, obj, false) existing, err := t.storage.(rest.Creater).Create(ctx, obj, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
...@@ -1128,7 +1128,7 @@ func (t *Tester) testGetMimatchedNamespace(obj runtime.Object) { ...@@ -1128,7 +1128,7 @@ func (t *Tester) testGetMimatchedNamespace(obj runtime.Object) {
objMeta := t.getObjectMetaOrFail(obj) objMeta := t.getObjectMetaOrFail(obj)
objMeta.SetName(t.namer(4)) objMeta.SetName(t.namer(4))
objMeta.SetNamespace(genericapirequest.NamespaceValue(ctx1)) objMeta.SetNamespace(genericapirequest.NamespaceValue(ctx1))
_, err := t.storage.(rest.Creater).Create(ctx1, obj, false) _, err := t.storage.(rest.Creater).Create(ctx1, obj, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
...@@ -1147,7 +1147,7 @@ func (t *Tester) testGetMimatchedNamespace(obj runtime.Object) { ...@@ -1147,7 +1147,7 @@ func (t *Tester) testGetMimatchedNamespace(obj runtime.Object) {
func (t *Tester) testGetNotFound(obj runtime.Object) { func (t *Tester) testGetNotFound(obj runtime.Object) {
ctx := t.TestContext() ctx := t.TestContext()
t.setObjectMeta(obj, t.namer(2)) t.setObjectMeta(obj, t.namer(2))
_, err := t.storage.(rest.Creater).Create(ctx, obj, false) _, err := t.storage.(rest.Creater).Create(ctx, obj, rest.ValidateAllObjectFunc, false)
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
......
...@@ -26,6 +26,7 @@ import ( ...@@ -26,6 +26,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/apiserver/pkg/admission"
genericapirequest "k8s.io/apiserver/pkg/endpoints/request" genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/features" "k8s.io/apiserver/pkg/features"
utilfeature "k8s.io/apiserver/pkg/util/feature" utilfeature "k8s.io/apiserver/pkg/util/feature"
...@@ -229,3 +230,28 @@ func (i *wrappedUpdatedObjectInfo) UpdatedObject(ctx genericapirequest.Context, ...@@ -229,3 +230,28 @@ func (i *wrappedUpdatedObjectInfo) UpdatedObject(ctx genericapirequest.Context,
return newObj, nil return newObj, nil
} }
// AdmissionToValidateObjectUpdateFunc converts validating admission to a rest validate object update func
func AdmissionToValidateObjectUpdateFunc(admit admission.Interface, staticAttributes admission.Attributes) ValidateObjectUpdateFunc {
validatingAdmission, ok := admit.(admission.ValidationInterface)
if !ok {
return func(obj, old runtime.Object) error { return nil }
}
return func(obj, old runtime.Object) error {
finalAttributes := admission.NewAttributesRecord(
obj,
old,
staticAttributes.GetKind(),
staticAttributes.GetNamespace(),
staticAttributes.GetName(),
staticAttributes.GetResource(),
staticAttributes.GetSubresource(),
staticAttributes.GetOperation(),
staticAttributes.GetUserInfo(),
)
if !validatingAdmission.Handles(finalAttributes.GetOperation()) {
return nil
}
return validatingAdmission.Validate(finalAttributes)
}
}
...@@ -72,6 +72,6 @@ func (r *StatusREST) New() runtime.Object { ...@@ -72,6 +72,6 @@ func (r *StatusREST) New() runtime.Object {
} }
// Update alters the status subset of an object. // Update alters the status subset of an object.
func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { func (r *StatusREST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo) return r.store.Update(ctx, name, objInfo, createValidation, updateValidation)
} }
...@@ -37,17 +37,17 @@ func Register(plugins *admission.Plugins) { ...@@ -37,17 +37,17 @@ func Register(plugins *admission.Plugins) {
}) })
} }
type disallowFlunder struct { type DisallowFlunder struct {
*admission.Handler *admission.Handler
lister listers.FischerLister lister listers.FischerLister
} }
var _ = wardleinitializer.WantsInternalWardleInformerFactory(&disallowFlunder{}) var _ = wardleinitializer.WantsInternalWardleInformerFactory(&DisallowFlunder{})
// Admit ensures that the object in-flight is of kind Flunder. // Admit ensures that the object in-flight is of kind Flunder.
// In addition checks that the Name is not on the banned list. // In addition checks that the Name is not on the banned list.
// The list is stored in Fischers API objects. // The list is stored in Fischers API objects.
func (d *disallowFlunder) Admit(a admission.Attributes) error { func (d *DisallowFlunder) Admit(a admission.Attributes) error {
// we are only interested in flunders // we are only interested in flunders
if a.GetKind().GroupKind() != wardle.Kind("Flunder") { if a.GetKind().GroupKind() != wardle.Kind("Flunder") {
return nil return nil
...@@ -80,12 +80,12 @@ func (d *disallowFlunder) Admit(a admission.Attributes) error { ...@@ -80,12 +80,12 @@ func (d *disallowFlunder) Admit(a admission.Attributes) error {
// SetInternalWardleInformerFactory gets Lister from SharedInformerFactory. // SetInternalWardleInformerFactory gets Lister from SharedInformerFactory.
// The lister knows how to lists Fischers. // The lister knows how to lists Fischers.
func (d *disallowFlunder) SetInternalWardleInformerFactory(f informers.SharedInformerFactory) { func (d *DisallowFlunder) SetInternalWardleInformerFactory(f informers.SharedInformerFactory) {
d.lister = f.Wardle().InternalVersion().Fischers().Lister() d.lister = f.Wardle().InternalVersion().Fischers().Lister()
} }
// Validate checks whether the plugin was correctly initialized. // ValidaValidateInitializationte checks whether the plugin was correctly initialized.
func (d *disallowFlunder) Validate() error { func (d *DisallowFlunder) ValidateInitialization() error {
if d.lister == nil { if d.lister == nil {
return fmt.Errorf("missing fischer lister") return fmt.Errorf("missing fischer lister")
} }
...@@ -93,8 +93,8 @@ func (d *disallowFlunder) Validate() error { ...@@ -93,8 +93,8 @@ func (d *disallowFlunder) Validate() error {
} }
// New creates a new ban flunder admission plugin // New creates a new ban flunder admission plugin
func New() (admission.Interface, error) { func New() (*DisallowFlunder, error) {
return &disallowFlunder{ return &DisallowFlunder{
Handler: admission.NewHandler(admission.Create), Handler: admission.NewHandler(admission.Create),
}, nil }, nil
} }
...@@ -119,7 +119,7 @@ func TestBanflunderAdmissionPlugin(t *testing.T) { ...@@ -119,7 +119,7 @@ func TestBanflunderAdmissionPlugin(t *testing.T) {
} }
targetInitializer.Initialize(target) targetInitializer.Initialize(target)
err = admission.Validate(target) err = admission.ValidateInitialization(target)
if err != nil { if err != nil {
t.Fatalf("scenario %d: failed to initialize banflunder admission plugin due to =%v", index, err) t.Fatalf("scenario %d: failed to initialize banflunder admission plugin due to =%v", index, err)
} }
......
...@@ -24,5 +24,5 @@ import ( ...@@ -24,5 +24,5 @@ import (
// WantsInternalWardleInformerFactory defines a function which sets InformerFactory for admission plugins that need it // WantsInternalWardleInformerFactory defines a function which sets InformerFactory for admission plugins that need it
type WantsInternalWardleInformerFactory interface { type WantsInternalWardleInformerFactory interface {
SetInternalWardleInformerFactory(informers.SharedInformerFactory) SetInternalWardleInformerFactory(informers.SharedInformerFactory)
admission.Validator admission.InitializationValidator
} }
...@@ -52,7 +52,7 @@ func (self *wantInternalWardleInformerFactory) SetInternalWardleInformerFactory( ...@@ -52,7 +52,7 @@ func (self *wantInternalWardleInformerFactory) SetInternalWardleInformerFactory(
} }
func (self *wantInternalWardleInformerFactory) Admit(a admission.Attributes) error { return nil } func (self *wantInternalWardleInformerFactory) Admit(a admission.Attributes) error { return nil }
func (self *wantInternalWardleInformerFactory) Handles(o admission.Operation) bool { return false } func (self *wantInternalWardleInformerFactory) Handles(o admission.Operation) bool { return false }
func (self *wantInternalWardleInformerFactory) Validate() error { return nil } func (self *wantInternalWardleInformerFactory) ValidateInitialization() error { return nil }
var _ admission.Interface = &wantInternalWardleInformerFactory{} var _ admission.Interface = &wantInternalWardleInformerFactory{}
var _ wardleinitializer.WantsInternalWardleInformerFactory = &wantInternalWardleInformerFactory{} var _ wardleinitializer.WantsInternalWardleInformerFactory = &wantInternalWardleInformerFactory{}
...@@ -83,7 +83,7 @@ func TestNodeAuthorizer(t *testing.T) { ...@@ -83,7 +83,7 @@ func TestNodeAuthorizer(t *testing.T) {
// Set up NodeRestriction admission // Set up NodeRestriction admission
nodeRestrictionAdmission := noderestriction.NewPlugin(nodeidentifier.NewDefaultNodeIdentifier()) nodeRestrictionAdmission := noderestriction.NewPlugin(nodeidentifier.NewDefaultNodeIdentifier())
nodeRestrictionAdmission.SetInternalKubeClientSet(superuserClient) nodeRestrictionAdmission.SetInternalKubeClientSet(superuserClient)
if err := nodeRestrictionAdmission.Validate(); err != nil { if err := nodeRestrictionAdmission.ValidateInitialization(); err != nil {
t.Fatal(err) t.Fatal(err)
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment