diff --git a/pkg/tools/etcd_tools.go b/pkg/tools/etcd_tools.go index a36cd74b628..0580a530346 100644 --- a/pkg/tools/etcd_tools.go +++ b/pkg/tools/etcd_tools.go @@ -249,7 +249,7 @@ type EtcdUpdateFunc func(input interface{}) (output interface{}, err error) // // Before this function is called, currentObj has been reset to etcd's current // // contents for "myKey". // -// cur := input.(*MyType) // Gauranteed to work. +// cur := input.(*MyType) // Guaranteed to work. // // // Make a *modification*. // cur.Counter++ @@ -290,6 +290,10 @@ func (h *EtcdHelper) AtomicUpdate(key string, ptrToType interface{}, tryUpdate E return err } + if string(data) == origBody { + return nil + } + _, err = h.Client.CompareAndSwap(key, string(data), 0, origBody, index) if IsEtcdTestFailed(err) { continue diff --git a/pkg/tools/etcd_tools_test.go b/pkg/tools/etcd_tools_test.go index 74deaacbe2a..21248ab1890 100644 --- a/pkg/tools/etcd_tools_test.go +++ b/pkg/tools/etcd_tools_test.go @@ -17,6 +17,7 @@ limitations under the License. package tools import ( + "errors" "fmt" "reflect" "sync" @@ -282,6 +283,37 @@ func TestAtomicUpdate(t *testing.T) { } } +func TestAtomicUpdateNoChange(t *testing.T) { + fakeClient := MakeFakeEtcdClient(t) + fakeClient.TestIndex = true + helper := EtcdHelper{fakeClient, scheme, api.NewJSONBaseResourceVersioner()} + + // Create a new node. + fakeClient.ExpectNotFoundGet("/some/key") + obj := &TestResource{JSONBase: api.JSONBase{ID: "foo"}, Value: 1} + err := helper.AtomicUpdate("/some/key", &TestResource{}, func(in interface{}) (interface{}, error) { + return obj, nil + }) + if err != nil { + t.Errorf("Unexpected error %#v", err) + } + + // Update an existing node with the same data + callbackCalled := false + objUpdate := &TestResource{JSONBase: api.JSONBase{ID: "foo"}, Value: 1} + fakeClient.Err = errors.New("should not be called") + err = helper.AtomicUpdate("/some/key", &TestResource{}, func(in interface{}) (interface{}, error) { + callbackCalled = true + return objUpdate, nil + }) + if err != nil { + t.Errorf("Unexpected error %#v", err) + } + if !callbackCalled { + t.Errorf("tryUpdate callback should have been called.") + } +} + func TestAtomicUpdate_CreateCollision(t *testing.T) { fakeClient := MakeFakeEtcdClient(t) fakeClient.TestIndex = true