From 3c25465855fdfad5c9108227b8d68955bb534f76 Mon Sep 17 00:00:00 2001 From: Iwasaki Yudai Date: Tue, 24 Apr 2018 18:47:30 -0700 Subject: [PATCH] etcdserver: Fix v2v3api set to create parent directly if not exists When a new file is created under an non existent directly, the v2 API automatically create the parent directly. This commit aligns the behaviour of v2v3 emulation to comply with the v2 API. --- etcdserver/api/v2v3/store.go | 18 ++++++++++++++---- etcdserver/v2store/store_test.go | 17 +++++++++++++++-- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/etcdserver/api/v2v3/store.go b/etcdserver/api/v2v3/store.go index c2b71370ed8..fd1dc78b3d4 100644 --- a/etcdserver/api/v2v3/store.go +++ b/etcdserver/api/v2v3/store.go @@ -143,10 +143,20 @@ func (s *v2v3Store) Set( ecode := 0 applyf := func(stm concurrency.STM) error { - parent := path.Dir(nodePath) - if !isRoot(parent) && stm.Rev(s.mkPath(parent)+"/") == 0 { - ecode = v2error.EcodeKeyNotFound - return nil + // build path if any directories in path do not exist + dirs := []string{} + for p := path.Dir(nodePath); !isRoot(p); p = path.Dir(p) { + pp := s.mkPath(p) + if stm.Rev(pp) > 0 { + ecode = v2error.EcodeNotDir + return nil + } + if stm.Rev(pp+"/") == 0 { + dirs = append(dirs, pp+"/") + } + } + for _, d := range dirs { + stm.Put(d, "") } key := s.mkPath(nodePath) diff --git a/etcdserver/v2store/store_test.go b/etcdserver/v2store/store_test.go index b385d9b5ce2..58b5bf1d5c8 100644 --- a/etcdserver/v2store/store_test.go +++ b/etcdserver/v2store/store_test.go @@ -145,8 +145,21 @@ func TestSet(t *testing.T) { testutil.AssertEqual(t, *e.PrevNode.Value, "bar") testutil.AssertEqual(t, e.PrevNode.ModifiedIndex, uint64(2)) - // Set /dir as a directory + // Set /a/b/c/d="efg" eidx = 4 + e, err = s.Set("/a/b/c/d", false, "efg", v2store.TTLOptionSet{ExpireTime: v2store.Permanent}) + testutil.AssertNil(t, err) + testutil.AssertEqual(t, e.EtcdIndex, eidx) + testutil.AssertEqual(t, e.Node.Key, "/a/b/c/d") + testutil.AssertFalse(t, e.Node.Dir) + testutil.AssertEqual(t, *e.Node.Value, "efg") + testutil.AssertNil(t, e.Node.Nodes) + testutil.AssertNil(t, e.Node.Expiration) + testutil.AssertEqual(t, e.Node.TTL, int64(0)) + testutil.AssertEqual(t, e.Node.ModifiedIndex, uint64(4)) + + // Set /dir as a directory + eidx = 5 e, err = s.Set("/dir", true, "", v2store.TTLOptionSet{ExpireTime: v2store.Permanent}) testutil.AssertNil(t, err) testutil.AssertEqual(t, e.EtcdIndex, eidx) @@ -157,7 +170,7 @@ func TestSet(t *testing.T) { testutil.AssertNil(t, e.Node.Nodes) testutil.AssertNil(t, e.Node.Expiration) testutil.AssertEqual(t, e.Node.TTL, int64(0)) - testutil.AssertEqual(t, e.Node.ModifiedIndex, uint64(4)) + testutil.AssertEqual(t, e.Node.ModifiedIndex, uint64(5)) } // Ensure that the store can create a new key if it doesn't already exist.