admission: wire create+update validation func into kube registries

Kubernetes-commit: 2452afffe09e1ced9487e5a701beb1443a92b741
This commit is contained in:
Dr. Stefan Schimanski 2017-10-24 15:33:28 +02:00 committed by Kubernetes Publisher
parent 441ac63056
commit 3eeded3a29
8 changed files with 114 additions and 99 deletions

View File

@ -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,

View File

@ -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")
}

View File

@ -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 {

View File

@ -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

View File

@ -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
}
}
}

View File

@ -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)
}

View File

@ -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.

View File

@ -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)
}