In GuaranteedUpdate, retry on any error if we are working with stale data

pull/564/head
Chao Xu 2019-05-08 15:05:07 -07:00
parent 66049e3b21
commit 0a7e849adf
2 changed files with 56 additions and 11 deletions

View File

@ -1851,3 +1851,47 @@ func TestMarkAsDeleting(t *testing.T) {
})
}
}
type staleGuaranteedUpdateStorage struct {
storage.Interface
cachedObj runtime.Object
}
// GuaranteedUpdate overwrites the method with one that always suggests the cachedObj.
func (s *staleGuaranteedUpdateStorage) GuaranteedUpdate(
ctx context.Context, key string, ptrToType runtime.Object, ignoreNotFound bool,
preconditions *storage.Preconditions, tryUpdate storage.UpdateFunc, _ ...runtime.Object) error {
return s.Interface.GuaranteedUpdate(ctx, key, ptrToType, ignoreNotFound, preconditions, tryUpdate, s.cachedObj)
}
func TestDeleteWithCachedObject(t *testing.T) {
podName := "foo"
podWithFinalizer := &example.Pod{
ObjectMeta: metav1.ObjectMeta{Name: podName, Finalizers: []string{"foo.com/x"}},
Spec: example.PodSpec{NodeName: "machine"},
}
podWithNoFinalizer := &example.Pod{
ObjectMeta: metav1.ObjectMeta{Name: podName},
Spec: example.PodSpec{NodeName: "machine"},
}
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), "test")
destroyFunc, registry := newTestGenericStoreRegistry(t, scheme, false)
defer destroyFunc()
// cached object does not have any finalizer.
registry.Storage.Storage = &staleGuaranteedUpdateStorage{Interface: registry.Storage.Storage, cachedObj: podWithNoFinalizer}
// created object with pending finalizer.
_, err := registry.Create(ctx, podWithFinalizer, rest.ValidateAllObjectFunc, &metav1.CreateOptions{})
if err != nil {
t.Fatal(err)
}
// The object shouldn't be deleted, because the persisted object has pending finalizers.
_, _, err = registry.Delete(ctx, podName, nil)
if err != nil {
t.Fatal(err)
}
// The object should still be there
_, err = registry.Get(ctx, podName, &metav1.GetOptions{})
if err != nil {
t.Fatal(err)
}
}

View File

@ -288,19 +288,20 @@ func (s *store) GuaranteedUpdate(
ret, ttl, err := s.updateState(origState, tryUpdate)
if err != nil {
// It's possible we were working with stale data
if mustCheckData && apierrors.IsConflict(err) {
// Actually fetch
origState, err = getCurrentState()
if err != nil {
return err
}
mustCheckData = false
// Retry
continue
// If our data is already up to date, return the error
if !mustCheckData {
return err
}
return err
// It's possible we were working with stale data
// Actually fetch
origState, err = getCurrentState()
if err != nil {
return err
}
mustCheckData = false
// Retry
continue
}
data, err := runtime.Encode(s.codec, ret)