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.