diff --git a/pkg/admission/chain_test.go b/pkg/admission/chain_test.go index 3a0dc7ce1..8bdd74ca4 100644 --- a/pkg/admission/chain_test.go +++ b/pkg/admission/chain_test.go @@ -25,9 +25,9 @@ import ( type FakeHandler struct { *Handler - name string - admit bool - admitCalled bool + name string + admit, admitCalled bool + validate, validateCalled bool } 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") } +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 { return &FakeHandler{ name: name, diff --git a/pkg/admission/plugin/namespace/lifecycle/admission.go b/pkg/admission/plugin/namespace/lifecycle/admission.go index e053a4907..b1384c2b9 100644 --- a/pkg/admission/plugin/namespace/lifecycle/admission.go +++ b/pkg/admission/plugin/namespace/lifecycle/admission.go @@ -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 -type lifecycle struct { +type Lifecycle struct { *admission.Handler client kubernetes.Interface immortalNamespaces sets.String @@ -73,8 +73,8 @@ type forceLiveLookupEntry struct { expiry time.Time } -var _ = initializer.WantsExternalKubeInformerFactory(&lifecycle{}) -var _ = initializer.WantsExternalKubeClientSet(&lifecycle{}) +var _ = initializer.WantsExternalKubeInformerFactory(&Lifecycle{}) +var _ = initializer.WantsExternalKubeClientSet(&Lifecycle{}) func makeNamespaceKey(namespace string) *v1.Namespace { return &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 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")) @@ -188,14 +188,14 @@ func (l *lifecycle) Admit(a admission.Attributes) error { return nil } -// NewLifecycle creates a new namespace lifecycle admission control handler -func NewLifecycle(immortalNamespaces sets.String) (admission.Interface, error) { +// NewLifecycle creates a new namespace Lifecycle admission control handler +func NewLifecycle(immortalNamespaces sets.String) (*Lifecycle, error) { 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) - return &lifecycle{ + return &Lifecycle{ Handler: admission.NewHandler(admission.Create, admission.Update, admission.Delete), immortalNamespaces: immortalNamespaces, forceLiveLookupCache: forceLiveLookupCache, @@ -203,19 +203,19 @@ func newLifecycleWithClock(immortalNamespaces sets.String, clock utilcache.Clock } // SetExternalKubeInformerFactory implements the WantsExternalKubeInformerFactory interface. -func (l *lifecycle) SetExternalKubeInformerFactory(f informers.SharedInformerFactory) { +func (l *Lifecycle) SetExternalKubeInformerFactory(f informers.SharedInformerFactory) { namespaceInformer := f.Core().V1().Namespaces() l.namespaceLister = namespaceInformer.Lister() l.SetReadyFunc(namespaceInformer.Informer().HasSynced) } // SetExternalKubeClientSet implements the WantsExternalKubeClientSet interface. -func (l *lifecycle) SetExternalKubeClientSet(client kubernetes.Interface) { +func (l *Lifecycle) SetExternalKubeClientSet(client kubernetes.Interface) { l.client = client } // Validate implement the Validator interface. -func (l *lifecycle) Validate() error { +func (l *Lifecycle) Validate() error { if l.namespaceLister == nil { return fmt.Errorf("missing namespaceLister") } diff --git a/pkg/admission/plugin/namespace/lifecycle/admission_test.go b/pkg/admission/plugin/namespace/lifecycle/admission_test.go index 5937eb643..4c885c21c 100644 --- a/pkg/admission/plugin/namespace/lifecycle/admission_test.go +++ b/pkg/admission/plugin/namespace/lifecycle/admission_test.go @@ -37,12 +37,12 @@ import ( ) // 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{}) } // 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) handler, err := newLifecycleWithClock(sets.NewString(metav1.NamespaceDefault, metav1.NamespaceSystem), cacheClock) if err != nil { diff --git a/pkg/endpoints/apiserver_test.go b/pkg/endpoints/apiserver_test.go index 4dd05a8be..458c4d2ac 100644 --- a/pkg/endpoints/apiserver_test.go +++ b/pkg/endpoints/apiserver_test.go @@ -519,7 +519,7 @@ func (storage *SimpleRESTStorage) NewList() runtime.Object { 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.created = obj.(*genericapitesting.Simple) if err := storage.errors["create"]; err != nil { @@ -532,7 +532,7 @@ func (storage *SimpleRESTStorage) Create(ctx request.Context, obj runtime.Object 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) obj, err := objInfo.UpdatedObject(ctx, &storage.item) if err != nil { @@ -714,7 +714,7 @@ type NamedCreaterRESTStorage struct { 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.created = obj.(*genericapitesting.Simple) storage.createdName = name diff --git a/pkg/endpoints/handlers/delete.go b/pkg/endpoints/handlers/delete.go index 3d72359c2..f2416d54a 100644 --- a/pkg/endpoints/handlers/delete.go +++ b/pkg/endpoints/handlers/delete.go @@ -94,23 +94,20 @@ func DeleteResource(r rest.GracefulDeleter, allowsOptions bool, scope RequestSco } trace.Step("About to check admission control") - if mutatingAdmission, ok := admit.(admission.MutationInterface); ok && mutatingAdmission.Handles(admission.Delete) { + if admit != nil && admit.Handles(admission.Delete) { userInfo, _ := request.UserFrom(ctx) - - err = mutatingAdmission.Admit(admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Delete, userInfo)) - if err != nil { - scope.err(err, w, req) - return + attrs := admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Delete, userInfo) + if mutatingAdmission, ok := admit.(admission.MutationInterface); ok { + if err := mutatingAdmission.Admit(attrs); 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) - - err = validatingAdmission.ValidatingAdmit(admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Delete, userInfo)) - if err != nil { - scope.err(err, w, req) - return + if validatingAdmission, ok := admit.(admission.ValidationInterface); ok { + if err := validatingAdmission.ValidatingAdmit(attrs); err != nil { + scope.err(err, w, req) + return + } } } diff --git a/pkg/registry/generic/registry/store_test.go b/pkg/registry/generic/registry/store_test.go index f9b9fcb7e..efa31cc3d 100644 --- a/pkg/registry/generic/registry/store_test.go +++ b/pkg/registry/generic/registry/store_test.go @@ -245,7 +245,7 @@ func TestStoreListResourceVersion(t *testing.T) { destroyFunc, registry := newTestGenericStoreRegistry(t, scheme, true) defer destroyFunc() - obj, err := registry.Create(ctx, fooPod, false) + obj, err := registry.Create(ctx, fooPod, rest.ValidateAllObjectFunc, false) if err != nil { t.Fatal(err) } @@ -275,7 +275,7 @@ func TestStoreListResourceVersion(t *testing.T) { 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) } @@ -312,7 +312,7 @@ func TestStoreCreate(t *testing.T) { registry.DeleteStrategy = testGracefulStrategy{defaultDeleteStrategy} // create the object - objA, err := registry.Create(testContext, podA, false) + objA, err := registry.Create(testContext, podA, rest.ValidateAllObjectFunc, false) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -329,7 +329,7 @@ func TestStoreCreate(t *testing.T) { } // 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) { t.Errorf("Unexpected error: %v", err) } @@ -348,7 +348,7 @@ func TestStoreCreate(t *testing.T) { } // 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) { t.Fatalf("Expected 'already exists' error from storage, but got %v", err) } @@ -440,7 +440,7 @@ func TestStoreCreateInitialized(t *testing.T) { } 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 { t.Fatal(err) } @@ -476,7 +476,7 @@ func TestStoreCreateInitialized(t *testing.T) { }() // create the object - objA, err := registry.Create(ctx, podA, false) + objA, err := registry.Create(ctx, podA, rest.ValidateAllObjectFunc, false) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -533,7 +533,7 @@ func TestStoreCreateInitializedFailed(t *testing.T) { } pod.Initializers.Pending = nil 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 { t.Fatal(err) } @@ -556,7 +556,7 @@ func TestStoreCreateInitializedFailed(t *testing.T) { }() // create the object - _, err := registry.Create(ctx, podA, false) + _, err := registry.Create(ctx, podA, rest.ValidateAllObjectFunc, false) if !errors.IsForbidden(err) { t.Fatalf("unexpected error: %#v", err.(errors.APIStatus).Status()) } @@ -574,7 +574,7 @@ func TestStoreCreateInitializedFailed(t *testing.T) { } 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 { t.Errorf("Unexpected error: %v", err) return false @@ -610,7 +610,7 @@ func TestStoreUpdate(t *testing.T) { defer destroyFunc() // 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) { t.Errorf("Unexpected error: %v", err) } @@ -623,7 +623,7 @@ func TestStoreUpdate(t *testing.T) { registry.UpdateStrategy.(*testRESTStrategy).allowCreateOnUpdate = false // 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) { t.Errorf("Unexpected error updating podAWithResourceVersion: %v", err) } @@ -660,7 +660,7 @@ func TestNoOpUpdates(t *testing.T) { var err error 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) } @@ -671,7 +671,7 @@ func TestNoOpUpdates(t *testing.T) { var updateResult runtime.Object 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) } @@ -835,7 +835,7 @@ func TestStoreDelete(t *testing.T) { } // create pod - _, err = registry.Create(testContext, podA, false) + _, err = registry.Create(testContext, podA, rest.ValidateAllObjectFunc, false) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -873,7 +873,7 @@ func TestStoreDeleteUninitialized(t *testing.T) { } // create pod - _, err = registry.Create(testContext, podA, true) + _, err = registry.Create(testContext, podA, rest.ValidateAllObjectFunc, true) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -950,7 +950,7 @@ func TestGracefulStoreHandleFinalizers(t *testing.T) { registry.EnableGarbageCollection = gcEnabled // create pod - _, err := registry.Create(testContext, podWithFinalizer, false) + _, err := registry.Create(testContext, podWithFinalizer, rest.ValidateAllObjectFunc, false) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -972,7 +972,7 @@ func TestGracefulStoreHandleFinalizers(t *testing.T) { ObjectMeta: metav1.ObjectMeta{Name: "foo", Finalizers: []string{"foo.com/x"}, ResourceVersion: podWithFinalizer.ObjectMeta.ResourceVersion}, 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 { t.Fatalf("Unexpected error: %v", err) } @@ -987,7 +987,7 @@ func TestGracefulStoreHandleFinalizers(t *testing.T) { ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: podWithFinalizer.ObjectMeta.ResourceVersion}, 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 { t.Fatalf("Unexpected error: %v", err) } @@ -1016,7 +1016,7 @@ func TestFailedInitializationStoreUpdate(t *testing.T) { defer destroyFunc() // create pod, view initializing - obj, err := registry.Create(testContext, podInitializing, true) + obj, err := registry.Create(testContext, podInitializing, rest.ValidateAllObjectFunc, true) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -1024,7 +1024,7 @@ func TestFailedInitializationStoreUpdate(t *testing.T) { // update the pod with initialization failure, the pod should be deleted 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 { t.Fatalf("Unexpected error: %v", err) } @@ -1055,7 +1055,7 @@ func TestNonGracefulStoreHandleFinalizers(t *testing.T) { registry.EnableGarbageCollection = gcEnabled // create pod - _, err := registry.Create(testContext, podWithFinalizer, false) + _, err := registry.Create(testContext, podWithFinalizer, rest.ValidateAllObjectFunc, false) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -1092,7 +1092,7 @@ func TestNonGracefulStoreHandleFinalizers(t *testing.T) { ObjectMeta: metav1.ObjectMeta{Name: "foo", Finalizers: []string{"foo.com/x"}, ResourceVersion: podWithFinalizer.ObjectMeta.ResourceVersion}, 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 { t.Errorf("Unexpected error: %v", err) } @@ -1111,7 +1111,7 @@ func TestNonGracefulStoreHandleFinalizers(t *testing.T) { ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: podWithFinalizer.ObjectMeta.ResourceVersion}, 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 { t.Errorf("Unexpected error: %v", err) } @@ -1357,7 +1357,7 @@ func TestStoreDeleteWithOrphanDependents(t *testing.T) { for _, tc := range testcases { registry.DeleteStrategy = tc.strategy // create pod - _, err := registry.Create(testContext, tc.pod, false) + _, err := registry.Create(testContext, tc.pod, rest.ValidateAllObjectFunc, false) if err != nil { t.Fatalf("Unexpected error: %v", err) } @@ -1576,7 +1576,7 @@ func TestStoreDeletionPropagation(t *testing.T) { i++ pod := createPod(i, tc.existingFinalizers) // create pod - _, err := registry.Create(testContext, pod, false) + _, err := registry.Create(testContext, pod, rest.ValidateAllObjectFunc, false) if err != nil { t.Fatalf("Unexpected error: %v", err) } @@ -1628,13 +1628,13 @@ func TestStoreDeleteCollection(t *testing.T) { destroyFunc, registry := NewTestGenericStoreRegistry(t) 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) } - 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) } - 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) } @@ -1670,10 +1670,10 @@ func TestStoreDeleteCollectionNotFound(t *testing.T) { for i := 0; i < 10; i++ { // 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) } - 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) } @@ -1709,7 +1709,7 @@ func TestStoreDeleteCollectionWithWatch(t *testing.T) { destroyFunc, registry := NewTestGenericStoreRegistry(t) defer destroyFunc() - objCreated, err := registry.Create(testContext, podA, false) + objCreated, err := registry.Create(testContext, podA, rest.ValidateAllObjectFunc, false) if err != nil { t.Fatalf("Unexpected error: %v", err) } @@ -1778,7 +1778,7 @@ func TestStoreWatch(t *testing.T) { if err != nil { t.Errorf("%v: unexpected error: %v", name, err) } else { - obj, err := registry.Create(testContext, podA, false) + obj, err := registry.Create(testContext, podA, rest.ValidateAllObjectFunc, false) if err != nil { got, open := <-wi.ResultChan() if !open { @@ -1922,7 +1922,7 @@ func TestQualifiedResource(t *testing.T) { defer destroyFunc() // 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) { t.Fatalf("Unexpected error: %v", err) } @@ -1954,13 +1954,13 @@ func TestQualifiedResource(t *testing.T) { } // create a non-exist object - _, err = registry.Create(testContext, podA, false) + _, err = registry.Create(testContext, podA, rest.ValidateAllObjectFunc, false) if err != nil { t.Fatal(err) } // create a exist object will fail - _, err = registry.Create(testContext, podA, false) + _, err = registry.Create(testContext, podA, rest.ValidateAllObjectFunc, false) if !errors.IsAlreadyExists(err) { t.Fatalf("Unexpected error: %v", err) } diff --git a/pkg/registry/rest/rest.go b/pkg/registry/rest/rest.go index 5a147b2a6..1155c8ade 100644 --- a/pkg/registry/rest/rest.go +++ b/pkg/registry/rest/rest.go @@ -226,11 +226,21 @@ type UpdatedObjectInfo interface { // 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. type Updater interface { // New returns an empty object that can be used with Update after request data has been put into it. diff --git a/pkg/registry/rest/resttest/resttest.go b/pkg/registry/rest/resttest/resttest.go index 1b19b6dea..110334546 100644 --- a/pkg/registry/rest/resttest/resttest.go +++ b/pkg/registry/rest/resttest/resttest.go @@ -244,7 +244,7 @@ func (t *Tester) testCreateAlreadyExisting(obj runtime.Object, createFn CreateFu } 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) { t.Errorf("expected already exists err, got %v", err) } @@ -256,7 +256,7 @@ func (t *Tester) testCreateEquals(obj runtime.Object, getFn GetFunc) { foo := obj.DeepCopyObject() 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 { t.Errorf("unexpected error: %v", err) } @@ -284,7 +284,7 @@ func (t *Tester) testCreateDiscardsObjectNamespace(valid runtime.Object) { objectMeta.SetNamespace("not-default") // 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 { t.Fatalf("Unexpected error: %v", err) } @@ -300,7 +300,7 @@ func (t *Tester) testCreateGeneratesName(valid runtime.Object) { objectMeta.SetName("") 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 { t.Fatalf("Unexpected error: %v", err) } @@ -315,7 +315,7 @@ func (t *Tester) testCreateHasMetadata(valid runtime.Object) { objectMeta.SetName(t.namer(1)) 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 { t.Fatalf("Unexpected error: %v", err) } @@ -333,7 +333,7 @@ func (t *Tester) testCreateIgnoresContextNamespace(valid runtime.Object) { ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), "not-default2") // 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 { t.Fatalf("Unexpected error: %v", err) } @@ -352,7 +352,7 @@ func (t *Tester) testCreateIgnoresMismatchedNamespace(valid runtime.Object) { ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), "not-default2") // 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 { t.Fatalf("Unexpected error: %v", err) } @@ -370,7 +370,7 @@ func (t *Tester) testCreateValidatesNames(valid runtime.Object) { objCopyMeta.SetName(invalidName) 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) { 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) { objCopyMeta.SetName(objCopyMeta.GetName() + invalidSuffix) 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) { 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) { func (t *Tester) testCreateInvokesValidation(invalid ...runtime.Object) { for i, obj := range invalid { 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) { 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) { objectMeta := t.getObjectMetaOrFail(valid) 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 { 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") { @@ -417,7 +417,7 @@ func (t *Tester) testCreateResetsUserData(valid runtime.Object) { objectMeta.SetUID("bad-uid") 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 { t.Fatalf("Unexpected error: %v", err) } @@ -435,7 +435,7 @@ func (t *Tester) testCreateIgnoreClusterName(valid runtime.Object) { objectMeta.SetName(t.namer(3)) 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 { t.Fatalf("Unexpected error: %v", err) } @@ -464,7 +464,7 @@ func (t *Tester) testUpdateEquals(obj runtime.Object, createFn CreateFunc, getFn } toUpdate = updateFn(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 { t.Errorf("unexpected error: %v", err) } @@ -504,7 +504,7 @@ func (t *Tester) testUpdateFailsOnVersionTooOld(obj runtime.Object, createFn Cre olderMeta := t.getObjectMetaOrFail(older) 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 { t.Errorf("Expected an error, but we didn't get one") } else if !errors.IsConflict(err) { @@ -524,7 +524,7 @@ func (t *Tester) testUpdateInvokesValidation(obj runtime.Object, createFn Create for _, update := range invalidUpdateFn { toUpdate := update(foo.DeepCopyObject()) 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 { 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, } 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 { 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 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 { t.Errorf("unexpected error: %v", err) return @@ -624,7 +624,7 @@ func (t *Tester) testUpdatePropagatesUpdatedObjectError(obj runtime.Object, crea 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 { t.Errorf("expected propagated error, got %#v", err) } @@ -650,7 +650,7 @@ func (t *Tester) testUpdateIgnoreGenerationUpdates(obj runtime.Object, createFn olderMeta := t.getObjectMetaOrFail(older) 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 { t.Errorf("Unexpected error: %v", err) } @@ -666,7 +666,7 @@ func (t *Tester) testUpdateIgnoreGenerationUpdates(obj runtime.Object, createFn func (t *Tester) testUpdateOnNotFound(obj runtime.Object) { 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 err != nil { t.Errorf("creation allowed on updated, but got an error: %v", err) @@ -701,7 +701,7 @@ func (t *Tester) testUpdateRejectsMismatchedNamespace(obj runtime.Object, create objectMeta.SetName(t.namer(1)) 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 { t.Errorf("expected nil object and not updated") } @@ -732,7 +732,7 @@ func (t *Tester) testUpdateIgnoreClusterName(obj runtime.Object, createFn Create olderMeta := t.getObjectMetaOrFail(older) 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 { t.Errorf("Unexpected error: %v", err) } @@ -1064,14 +1064,14 @@ func (t *Tester) testGetDifferentNamespace(obj runtime.Object) { ctx1 := genericapirequest.WithNamespace(genericapirequest.NewContext(), "bar3") 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 { t.Errorf("unexpected error: %v", err) } ctx2 := genericapirequest.WithNamespace(genericapirequest.NewContext(), "bar4") 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 { t.Errorf("unexpected error: %v", err) } @@ -1105,7 +1105,7 @@ func (t *Tester) testGetFound(obj runtime.Object) { ctx := t.TestContext() 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 { t.Errorf("unexpected error: %v", err) } @@ -1128,7 +1128,7 @@ func (t *Tester) testGetMimatchedNamespace(obj runtime.Object) { objMeta := t.getObjectMetaOrFail(obj) objMeta.SetName(t.namer(4)) 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 { t.Errorf("unexpected error: %v", err) } @@ -1147,7 +1147,7 @@ func (t *Tester) testGetMimatchedNamespace(obj runtime.Object) { func (t *Tester) testGetNotFound(obj runtime.Object) { ctx := t.TestContext() 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 { t.Errorf("unexpected error: %v", err) }