Browse Source

v1: deprecate v1 support

Etcd moves to 0.5 without the support of v1.
Yicheng Qin 11 years ago
parent
commit
02ced2c2d7

+ 3 - 12
Documentation/clients-matrix.md

@@ -1,7 +1,6 @@
 # Client libraries support matrix for etcd
 
 As etcd features support is really uneven between client libraries, a compatibility matrix can be important.
-We will consider in detail only the features of clients supporting the v2 API. Clients still supporting the v1 API *only* are listed below.
 
 ## v2 clients
 
@@ -14,6 +13,7 @@ The v2 API has a lot of features, we will categorize them in a few categories:
 - **GET,PUT,POST,DEL Features**: Support for all the modifiers when calling the etcd server with said HTTP method.
 
 ### Supported features matrix
+
 **Legend**
 **F**: Full support **G**: Good support **B**: Basic support
 **Y**: Feature supported  **-**: Feature not supported
@@ -30,6 +30,7 @@ Sorted alphabetically on language/name
 |[go-etcd](https://github.com/coreos/go-etcd)                     |go     |Y|Y|F|F|F|F|-|-|
 |[etcd4j](https://github.com/jurmous/etcd4j)                      |java   |Y|Y|F|F|F|F|-|-|
 |[jetcd](https://github.com/diwakergupta/jetcd)                   |java   |Y|-|B|B|-|B|-|-|
+|[jetcd](https://github.com/justinsb/jetcd)                       |java   |-|-|B|B|-|B|-|-|
 |[Etcd.jl](https://github.com/forio/Etcd.jl)                      |Julia  |-|-|F|F|F|F|Y|Y|
 |[etcetera](https://github.com/drusellers/etcetera)               |.net   |-|-|F|F|F|F|-|-|
 |[node-etcd](https://github.com/stianeikeland/node-etcd)          |nodejs |Y|-|F|F|-|F|-|-|
@@ -37,15 +38,5 @@ Sorted alphabetically on language/name
 |[p5-etcd](https://metacpan.org/release/Etcd)                     |perl   |-|-|F|F|F|F|-|-|
 |[python-etcd](https://github.com/jplana/python-etcd)             |python |Y|Y|F|F|F|F|Y|-|
 |[python-etcd-client](https://github.com/dsoprea/PythonEtcdClient)|python |Y|Y|F|F|F|F|Y|Y|
+|[txetcd](https://github.com/russellhaering/txetcd)               |python |-|-|G|G|F|G|-|-|
 |[etcd-ruby](https://github.com/ranjib/etcd-ruby)                 |ruby   |-|-|F|F|F|F|-|-|
-
-## v1-only clients
-
-Clients supporting only the API version 1
-
-- [justinsb/jetcd](https://github.com/justinsb/jetcd) Java
-- [transitorykris/etcd-py](https://github.com/transitorykris/etcd-py) Python
-- [russellhaering/txetcd](https://github.com/russellhaering/txetcd) Python
-- [iconara/etcd-rb](https://github.com/iconara/etcd-rb) Ruby
-- [jpfuentes2/etcd-ruby](https://github.com/jpfuentes2/etcd-ruby) Ruby
-- [marshall-lee/etcd.erl](https://github.com/marshall-lee/etcd.erl) Erlang

+ 2 - 2
README.md

@@ -120,10 +120,10 @@ curl -L http://127.0.0.1:4001/version
 
 #### API Versioning
 
-Clients are encouraged to use the `v2` API. The `v1` API will not change.
-
 The `v2` API responses should not change after the 0.2.0 release but new features will be added over time.
 
+The `v1` API has been deprecated and will not be supported.
+
 During the pre-v1.0.0 series of releases we may break the API as we fix bugs and get feedback.
 
 #### 32bit systems

+ 13 - 41
server/server.go

@@ -17,7 +17,6 @@ import (
 	"github.com/coreos/etcd/metrics"
 	"github.com/coreos/etcd/mod"
 	uhttp "github.com/coreos/etcd/pkg/http"
-	"github.com/coreos/etcd/server/v1"
 	"github.com/coreos/etcd/server/v2"
 	"github.com/coreos/etcd/store"
 	_ "github.com/coreos/etcd/store/v2"
@@ -107,19 +106,6 @@ func (s *Server) SetStore(store store.Store) {
 	s.store = store
 }
 
-func (s *Server) installV1(r *mux.Router) {
-	s.handleFuncV1(r, "/v1/keys/{key:.*}", v1.GetKeyHandler).Methods("GET", "HEAD")
-	s.handleFuncV1(r, "/v1/keys/{key:.*}", v1.SetKeyHandler).Methods("POST", "PUT")
-	s.handleFuncV1(r, "/v1/keys/{key:.*}", v1.DeleteKeyHandler).Methods("DELETE")
-	s.handleFuncV1(r, "/v1/watch/{key:.*}", v1.WatchKeyHandler).Methods("GET", "HEAD", "POST")
-	s.handleFunc(r, "/v1/leader", s.GetLeaderHandler).Methods("GET", "HEAD")
-	s.handleFunc(r, "/v1/machines", s.GetPeersHandler).Methods("GET", "HEAD")
-	s.handleFunc(r, "/v1/peers", s.GetPeersHandler).Methods("GET", "HEAD")
-	s.handleFunc(r, "/v1/stats/self", s.GetStatsHandler).Methods("GET", "HEAD")
-	s.handleFunc(r, "/v1/stats/leader", s.GetLeaderStatsHandler).Methods("GET", "HEAD")
-	s.handleFunc(r, "/v1/stats/store", s.GetStoreStatsHandler).Methods("GET", "HEAD")
-}
-
 func (s *Server) installV2(r *mux.Router) {
 	r2 := mux.NewRouter()
 	r.PathPrefix("/v2").Handler(ehttp.NewLowerQueryParamsHandler(r2))
@@ -150,13 +136,6 @@ func (s *Server) installDebug(r *mux.Router) {
 	r.HandleFunc("/debug/pprof/{name}", pprof.Index)
 }
 
-// Adds a v1 server handler to the router.
-func (s *Server) handleFuncV1(r *mux.Router, path string, f func(http.ResponseWriter, *http.Request, v1.Server) error) *mux.Route {
-	return s.handleFunc(r, path, func(w http.ResponseWriter, req *http.Request) error {
-		return f(w, req, s)
-	})
-}
-
 // Adds a v2 server handler to the router.
 func (s *Server) handleFuncV2(r *mux.Router, path string, f func(http.ResponseWriter, *http.Request, v2.Server) error) *mux.Route {
 	return s.handleFunc(r, path, func(w http.ResponseWriter, req *http.Request) error {
@@ -202,7 +181,6 @@ func (s *Server) HTTPHandler() http.Handler {
 
 	// Install the routes.
 	s.handleFunc(router, "/version", s.GetVersionHandler).Methods("GET")
-	s.installV1(router)
 	s.installV2(router)
 	// Mod is deprecated temporariy due to its unstable state.
 	// It would be added back later.
@@ -235,26 +213,20 @@ func (s *Server) Dispatch(c raft.Command, w http.ResponseWriter, req *http.Reque
 			return nil
 		}
 
-		var b []byte
-		if strings.HasPrefix(req.URL.Path, "/v1") {
-			b, _ = json.Marshal(result.(*store.Event).Response(0))
-			w.WriteHeader(http.StatusOK)
+		e, _ := result.(*store.Event)
+		b, _ := json.Marshal(e)
+
+		w.Header().Set("Content-Type", "application/json")
+		// etcd index should be the same as the event index
+		// which is also the last modified index of the node
+		w.Header().Add("X-Etcd-Index", fmt.Sprint(e.Index()))
+		w.Header().Add("X-Raft-Index", fmt.Sprint(s.CommitIndex()))
+		w.Header().Add("X-Raft-Term", fmt.Sprint(s.Term()))
+
+		if e.IsCreated() {
+			w.WriteHeader(http.StatusCreated)
 		} else {
-			e, _ := result.(*store.Event)
-			b, _ = json.Marshal(e)
-
-			w.Header().Set("Content-Type", "application/json")
-			// etcd index should be the same as the event index
-			// which is also the last modified index of the node
-			w.Header().Add("X-Etcd-Index", fmt.Sprint(e.Index()))
-			w.Header().Add("X-Raft-Index", fmt.Sprint(s.CommitIndex()))
-			w.Header().Add("X-Raft-Term", fmt.Sprint(s.Term()))
-
-			if e.IsCreated() {
-				w.WriteHeader(http.StatusCreated)
-			} else {
-				w.WriteHeader(http.StatusOK)
-			}
+			w.WriteHeader(http.StatusOK)
 		}
 
 		w.Write(b)

+ 0 - 15
server/v1/delete_key_handler.go

@@ -1,15 +0,0 @@
-package v1
-
-import (
-	"net/http"
-
-	"github.com/coreos/etcd/third_party/github.com/gorilla/mux"
-)
-
-// Removes a key from the store.
-func DeleteKeyHandler(w http.ResponseWriter, req *http.Request, s Server) error {
-	vars := mux.Vars(req)
-	key := "/" + vars["key"]
-	c := s.Store().CommandFactory().CreateDeleteCommand(key, false, false)
-	return s.Dispatch(c, w, req)
-}

+ 0 - 31
server/v1/get_key_handler.go

@@ -1,31 +0,0 @@
-package v1
-
-import (
-	"encoding/json"
-	"net/http"
-
-	"github.com/coreos/etcd/third_party/github.com/gorilla/mux"
-)
-
-// Retrieves the value for a given key.
-func GetKeyHandler(w http.ResponseWriter, req *http.Request, s Server) error {
-	vars := mux.Vars(req)
-	key := "/" + vars["key"]
-
-	// Retrieve the key from the store.
-	event, err := s.Store().Get(key, false, false)
-	if err != nil {
-		return err
-	}
-
-	w.WriteHeader(http.StatusOK)
-
-	if req.Method == "HEAD" {
-		return nil
-	}
-
-	// Convert event to a response and write to client.
-	b, _ := json.Marshal(event.Response(s.Store().Index()))
-	w.Write(b)
-	return nil
-}

+ 0 - 47
server/v1/set_key_handler.go

@@ -1,47 +0,0 @@
-package v1
-
-import (
-	"net/http"
-
-	etcdErr "github.com/coreos/etcd/error"
-	"github.com/coreos/etcd/store"
-	"github.com/coreos/etcd/third_party/github.com/goraft/raft"
-	"github.com/coreos/etcd/third_party/github.com/gorilla/mux"
-)
-
-// Sets the value for a given key.
-func SetKeyHandler(w http.ResponseWriter, req *http.Request, s Server) error {
-	vars := mux.Vars(req)
-	key := "/" + vars["key"]
-
-	req.ParseForm()
-
-	// Parse non-blank value.
-	value := req.Form.Get("value")
-	if len(value) == 0 {
-		return etcdErr.NewError(200, "Set", s.Store().Index())
-	}
-
-	// Convert time-to-live to an expiration time.
-	expireTime, err := store.TTL(req.Form.Get("ttl"))
-	if err != nil {
-		return etcdErr.NewError(202, "Set", s.Store().Index())
-	}
-
-	// If the "prevValue" is specified then test-and-set. Otherwise create a new key.
-	var c raft.Command
-	if prevValueArr, ok := req.Form["prevValue"]; ok {
-		if len(prevValueArr[0]) > 0 {
-			// test against previous value
-			c = s.Store().CommandFactory().CreateCompareAndSwapCommand(key, value, prevValueArr[0], 0, expireTime)
-		} else {
-			// test against existence
-			c = s.Store().CommandFactory().CreateCreateCommand(key, false, value, expireTime, false)
-		}
-
-	} else {
-		c = s.Store().CommandFactory().CreateSetCommand(key, false, value, expireTime)
-	}
-
-	return s.Dispatch(c, w, req)
-}

+ 0 - 31
server/v1/tests/delete_handler_test.go

@@ -1,31 +0,0 @@
-package v1
-
-import (
-	"fmt"
-	"net/http"
-	"net/url"
-	"testing"
-
-	"github.com/coreos/etcd/server"
-	"github.com/coreos/etcd/tests"
-	"github.com/coreos/etcd/third_party/github.com/stretchr/testify/assert"
-)
-
-// Ensures that a key is deleted.
-//
-//   $ curl -X PUT localhost:4001/v1/keys/foo/bar -d value=XXX
-//   $ curl -X DELETE localhost:4001/v1/keys/foo/bar
-//
-func TestV1DeleteKey(t *testing.T) {
-	tests.RunServer(func(s *server.Server) {
-		v := url.Values{}
-		v.Set("value", "XXX")
-		resp, err := tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v1/keys/foo/bar"), v)
-		tests.ReadBody(resp)
-		resp, err = tests.DeleteForm(fmt.Sprintf("%s%s", s.URL(), "/v1/keys/foo/bar"), url.Values{})
-		assert.Equal(t, resp.StatusCode, http.StatusOK)
-		body := tests.ReadBody(resp)
-		assert.Nil(t, err, "")
-		assert.Equal(t, string(body), `{"action":"delete","key":"/foo/bar","prevValue":"XXX","index":4}`, "")
-	})
-}

+ 0 - 209
server/v1/tests/get_handler_test.go

@@ -1,209 +0,0 @@
-package v1
-
-import (
-	"encoding/json"
-	"fmt"
-	"net/http"
-	"net/url"
-	"testing"
-	"time"
-
-	"github.com/coreos/etcd/server"
-	"github.com/coreos/etcd/tests"
-	"github.com/coreos/etcd/third_party/github.com/stretchr/testify/assert"
-)
-
-// Ensures that a value can be retrieve for a given key.
-//
-//   $ curl localhost:4001/v1/keys/foo/bar -> fail
-//   $ curl -X PUT localhost:4001/v1/keys/foo/bar -d value=XXX
-//   $ curl localhost:4001/v1/keys/foo/bar
-//
-func TestV1GetKey(t *testing.T) {
-	tests.RunServer(func(s *server.Server) {
-		v := url.Values{}
-		v.Set("value", "XXX")
-		fullURL := fmt.Sprintf("%s%s", s.URL(), "/v1/keys/foo/bar")
-		resp, _ := tests.Get(fullURL)
-		assert.Equal(t, resp.StatusCode, http.StatusNotFound)
-
-		resp, _ = tests.PutForm(fullURL, v)
-		tests.ReadBody(resp)
-
-		resp, _ = tests.Get(fullURL)
-		assert.Equal(t, resp.StatusCode, http.StatusOK)
-		body := tests.ReadBodyJSON(resp)
-		assert.Equal(t, body["action"], "get", "")
-		assert.Equal(t, body["key"], "/foo/bar", "")
-		assert.Equal(t, body["value"], "XXX", "")
-		assert.Equal(t, body["index"], 3, "")
-	})
-}
-
-// Ensures that a directory of values can be retrieved for a given key.
-//
-//   $ curl -X PUT localhost:4001/v1/keys/foo/x -d value=XXX
-//   $ curl -X PUT localhost:4001/v1/keys/foo/y/z -d value=YYY
-//   $ curl localhost:4001/v1/keys/foo
-//
-func TestV1GetKeyDir(t *testing.T) {
-	tests.RunServer(func(s *server.Server) {
-		v := url.Values{}
-		v.Set("value", "XXX")
-		resp, _ := tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v1/keys/foo/x"), v)
-		tests.ReadBody(resp)
-
-		v.Set("value", "YYY")
-		resp, _ = tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v1/keys/foo/y/z"), v)
-		tests.ReadBody(resp)
-
-		resp, _ = tests.Get(fmt.Sprintf("%s%s", s.URL(), "/v1/keys/foo"))
-		assert.Equal(t, resp.StatusCode, http.StatusOK)
-		body := tests.ReadBody(resp)
-		nodes := make([]interface{}, 0)
-		if err := json.Unmarshal(body, &nodes); err != nil {
-			panic(fmt.Sprintf("HTTP body JSON parse error: %v", err))
-		}
-		assert.Equal(t, len(nodes), 2, "")
-
-		node0 := nodes[0].(map[string]interface{})
-		assert.Equal(t, node0["action"], "get", "")
-		assert.Equal(t, node0["key"], "/foo/x", "")
-		assert.Equal(t, node0["value"], "XXX", "")
-
-		node1 := nodes[1].(map[string]interface{})
-		assert.Equal(t, node1["action"], "get", "")
-		assert.Equal(t, node1["key"], "/foo/y", "")
-		assert.Equal(t, node1["dir"], true, "")
-	})
-}
-
-// Ensures that a watcher can wait for a value to be set and return it to the client.
-//
-//   $ curl localhost:4001/v1/watch/foo/bar
-//   $ curl -X PUT localhost:4001/v1/keys/foo/bar -d value=XXX
-//
-func TestV1WatchKey(t *testing.T) {
-	tests.RunServer(func(s *server.Server) {
-		// There exists a little gap between etcd ready to serve and
-		// it actually serves the first request, which means the response
-		// delay could be a little bigger.
-		// This test is time sensitive, so it does one request to ensure
-		// that the server is working.
-		tests.Get(fmt.Sprintf("%s%s", s.URL(), "/v1/keys/foo/bar"))
-
-		var watchResp *http.Response
-		c := make(chan bool)
-		go func() {
-			watchResp, _ = tests.Get(fmt.Sprintf("%s%s", s.URL(), "/v1/watch/foo/bar"))
-			c <- true
-		}()
-
-		// Make sure response didn't fire early.
-		time.Sleep(1 * time.Millisecond)
-
-		// Set a value.
-		v := url.Values{}
-		v.Set("value", "XXX")
-		resp, _ := tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v1/keys/foo/bar"), v)
-		tests.ReadBody(resp)
-
-		// A response should follow from the GET above.
-		time.Sleep(1 * time.Millisecond)
-
-		select {
-		case <-c:
-
-		default:
-			t.Fatal("cannot get watch result")
-		}
-
-		body := tests.ReadBodyJSON(watchResp)
-		assert.NotNil(t, body, "")
-		assert.Equal(t, body["action"], "set", "")
-
-		assert.Equal(t, body["key"], "/foo/bar", "")
-		assert.Equal(t, body["value"], "XXX", "")
-		assert.Equal(t, body["index"], 3, "")
-	})
-}
-
-// Ensures that a watcher can wait for a value to be set after a given index.
-//
-//   $ curl -X POST localhost:4001/v1/watch/foo/bar -d index=4
-//   $ curl -X PUT localhost:4001/v1/keys/foo/bar -d value=XXX
-//   $ curl -X PUT localhost:4001/v1/keys/foo/bar -d value=YYY
-//
-func TestV1WatchKeyWithIndex(t *testing.T) {
-	tests.RunServer(func(s *server.Server) {
-		var body map[string]interface{}
-		c := make(chan bool)
-		go func() {
-			v := url.Values{}
-			v.Set("index", "4")
-			resp, _ := tests.PostForm(fmt.Sprintf("%s%s", s.URL(), "/v1/watch/foo/bar"), v)
-			body = tests.ReadBodyJSON(resp)
-			c <- true
-		}()
-
-		// Make sure response didn't fire early.
-		time.Sleep(1 * time.Millisecond)
-		assert.Nil(t, body, "")
-
-		// Set a value (before given index).
-		v := url.Values{}
-		v.Set("value", "XXX")
-		resp, _ := tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v1/keys/foo/bar"), v)
-		tests.ReadBody(resp)
-
-		// Make sure response didn't fire early.
-		time.Sleep(1 * time.Millisecond)
-		assert.Nil(t, body, "")
-
-		// Set a value (before given index).
-		v.Set("value", "YYY")
-		resp, _ = tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v1/keys/foo/bar"), v)
-		tests.ReadBody(resp)
-
-		// A response should follow from the GET above.
-		time.Sleep(1 * time.Millisecond)
-
-		select {
-		case <-c:
-
-		default:
-			t.Fatal("cannot get watch result")
-		}
-
-		assert.NotNil(t, body, "")
-		assert.Equal(t, body["action"], "set", "")
-
-		assert.Equal(t, body["key"], "/foo/bar", "")
-		assert.Equal(t, body["value"], "YYY", "")
-		assert.Equal(t, body["index"], 4, "")
-	})
-}
-
-// Ensures that HEAD works.
-//
-//   $ curl -I localhost:4001/v1/keys/foo/bar -> fail
-//   $ curl -X PUT localhost:4001/v1/keys/foo/bar -d value=XXX
-//   $ curl -I localhost:4001/v1/keys/foo/bar
-//
-func TestV1HeadKey(t *testing.T) {
-	tests.RunServer(func(s *server.Server) {
-		v := url.Values{}
-		v.Set("value", "XXX")
-		fullURL := fmt.Sprintf("%s%s", s.URL(), "/v1/keys/foo/bar")
-		resp, _ := tests.Get(fullURL)
-		assert.Equal(t, resp.StatusCode, http.StatusNotFound)
-		assert.Equal(t, resp.ContentLength, -1)
-
-		resp, _ = tests.PutForm(fullURL, v)
-		tests.ReadBody(resp)
-
-		resp, _ = tests.Get(fullURL)
-		assert.Equal(t, resp.StatusCode, http.StatusOK)
-		assert.Equal(t, resp.ContentLength, -1)
-	})
-}

+ 0 - 157
server/v1/tests/put_handler_test.go

@@ -1,157 +0,0 @@
-package v1
-
-import (
-	"fmt"
-	"net/http"
-	"net/url"
-	"testing"
-	"time"
-
-	"github.com/coreos/etcd/server"
-	"github.com/coreos/etcd/tests"
-	"github.com/coreos/etcd/third_party/github.com/stretchr/testify/assert"
-)
-
-// Ensures that a key is set to a given value.
-//
-//   $ curl -X PUT localhost:4001/v1/keys/foo/bar -d value=XXX
-//
-func TestV1SetKey(t *testing.T) {
-	tests.RunServer(func(s *server.Server) {
-		v := url.Values{}
-		v.Set("value", "XXX")
-		resp, err := tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v1/keys/foo/bar"), v)
-		assert.Equal(t, resp.StatusCode, http.StatusOK)
-		body := tests.ReadBody(resp)
-		assert.Nil(t, err, "")
-
-		assert.Equal(t, string(body), `{"action":"set","key":"/foo/bar","value":"XXX","newKey":true,"index":3}`, "")
-	})
-}
-
-// Ensures that a time-to-live is added to a key.
-//
-//   $ curl -X PUT localhost:4001/v1/keys/foo/bar -d value=XXX -d ttl=20
-//
-func TestV1SetKeyWithTTL(t *testing.T) {
-	tests.RunServer(func(s *server.Server) {
-		t0 := time.Now()
-		v := url.Values{}
-		v.Set("value", "XXX")
-		v.Set("ttl", "20")
-		resp, _ := tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v1/keys/foo/bar"), v)
-		assert.Equal(t, resp.StatusCode, http.StatusOK)
-		body := tests.ReadBodyJSON(resp)
-		assert.Equal(t, body["ttl"], 20, "")
-
-		// Make sure the expiration date is correct.
-		expiration, _ := time.Parse(time.RFC3339Nano, body["expiration"].(string))
-		assert.Equal(t, expiration.Sub(t0)/time.Second, 20, "")
-	})
-}
-
-// Ensures that an invalid time-to-live is returned as an error.
-//
-//   $ curl -X PUT localhost:4001/v1/keys/foo/bar -d value=XXX -d ttl=bad_ttl
-//
-func TestV1SetKeyWithBadTTL(t *testing.T) {
-	tests.RunServer(func(s *server.Server) {
-		v := url.Values{}
-		v.Set("value", "XXX")
-		v.Set("ttl", "bad_ttl")
-		resp, _ := tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v1/keys/foo/bar"), v)
-		assert.Equal(t, resp.StatusCode, http.StatusBadRequest)
-		body := tests.ReadBodyJSON(resp)
-		assert.Equal(t, body["errorCode"], 202, "")
-		assert.Equal(t, body["message"], "The given TTL in POST form is not a number", "")
-		assert.Equal(t, body["cause"], "Set", "")
-	})
-}
-
-// Ensures that a key is conditionally set if it previously did not exist.
-//
-//   $ curl -X PUT localhost:4001/v1/keys/foo/bar -d value=XXX -d prevValue=
-//
-func TestV1CreateKeySuccess(t *testing.T) {
-	tests.RunServer(func(s *server.Server) {
-		v := url.Values{}
-		v.Set("value", "XXX")
-		v.Set("prevValue", "")
-		resp, _ := tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v1/keys/foo/bar"), v)
-		assert.Equal(t, resp.StatusCode, http.StatusOK)
-		body := tests.ReadBodyJSON(resp)
-		assert.Equal(t, body["value"], "XXX", "")
-	})
-}
-
-// Ensures that a key is not conditionally set because it previously existed.
-//
-//   $ curl -X PUT localhost:4001/v1/keys/foo/bar -d value=XXX -d prevValue=
-//   $ curl -X PUT localhost:4001/v1/keys/foo/bar -d value=XXX -d prevValue= -> fail
-//
-func TestV1CreateKeyFail(t *testing.T) {
-	tests.RunServer(func(s *server.Server) {
-		v := url.Values{}
-		v.Set("value", "XXX")
-		v.Set("prevValue", "")
-		fullURL := fmt.Sprintf("%s%s", s.URL(), "/v1/keys/foo/bar")
-		resp, _ := tests.PutForm(fullURL, v)
-		assert.Equal(t, resp.StatusCode, http.StatusOK)
-		tests.ReadBody(resp)
-		resp, _ = tests.PutForm(fullURL, v)
-		assert.Equal(t, resp.StatusCode, http.StatusPreconditionFailed)
-		body := tests.ReadBodyJSON(resp)
-		assert.Equal(t, body["errorCode"], 105, "")
-		assert.Equal(t, body["message"], "Key already exists", "")
-		assert.Equal(t, body["cause"], "/foo/bar", "")
-	})
-}
-
-// Ensures that a key is set only if the previous value matches.
-//
-//   $ curl -X PUT localhost:4001/v1/keys/foo/bar -d value=XXX
-//   $ curl -X PUT localhost:4001/v1/keys/foo/bar -d value=YYY -d prevValue=XXX
-//
-func TestV1SetKeyCASOnValueSuccess(t *testing.T) {
-	tests.RunServer(func(s *server.Server) {
-		v := url.Values{}
-		v.Set("value", "XXX")
-		fullURL := fmt.Sprintf("%s%s", s.URL(), "/v1/keys/foo/bar")
-		resp, _ := tests.PutForm(fullURL, v)
-		assert.Equal(t, resp.StatusCode, http.StatusOK)
-		tests.ReadBody(resp)
-		v.Set("value", "YYY")
-		v.Set("prevValue", "XXX")
-		resp, _ = tests.PutForm(fullURL, v)
-		assert.Equal(t, resp.StatusCode, http.StatusOK)
-		body := tests.ReadBodyJSON(resp)
-		assert.Equal(t, body["action"], "testAndSet", "")
-		assert.Equal(t, body["value"], "YYY", "")
-		assert.Equal(t, body["index"], 4, "")
-	})
-}
-
-// Ensures that a key is not set if the previous value does not match.
-//
-//   $ curl -X PUT localhost:4001/v1/keys/foo/bar -d value=XXX
-//   $ curl -X PUT localhost:4001/v1/keys/foo/bar -d value=YYY -d prevValue=AAA
-//
-func TestV1SetKeyCASOnValueFail(t *testing.T) {
-	tests.RunServer(func(s *server.Server) {
-		v := url.Values{}
-		v.Set("value", "XXX")
-		fullURL := fmt.Sprintf("%s%s", s.URL(), "/v1/keys/foo/bar")
-		resp, _ := tests.PutForm(fullURL, v)
-		assert.Equal(t, resp.StatusCode, http.StatusOK)
-		tests.ReadBody(resp)
-		v.Set("value", "YYY")
-		v.Set("prevValue", "AAA")
-		resp, _ = tests.PutForm(fullURL, v)
-		assert.Equal(t, resp.StatusCode, http.StatusPreconditionFailed)
-		body := tests.ReadBodyJSON(resp)
-		assert.Equal(t, body["errorCode"], 101, "")
-		assert.Equal(t, body["message"], "Compare failed", "")
-		assert.Equal(t, body["cause"], "[AAA != XXX]", "")
-		assert.Equal(t, body["index"], 3, "")
-	})
-}

+ 0 - 16
server/v1/v1.go

@@ -1,16 +0,0 @@
-package v1
-
-import (
-	"net/http"
-
-	"github.com/coreos/etcd/store"
-	"github.com/coreos/etcd/third_party/github.com/goraft/raft"
-)
-
-// The Server interface provides all the methods required for the v1 API.
-type Server interface {
-	CommitIndex() uint64
-	Term() uint64
-	Store() store.Store
-	Dispatch(raft.Command, http.ResponseWriter, *http.Request) error
-}

+ 0 - 42
server/v1/watch_key_handler.go

@@ -1,42 +0,0 @@
-package v1
-
-import (
-	"encoding/json"
-	"net/http"
-	"strconv"
-
-	etcdErr "github.com/coreos/etcd/error"
-	"github.com/coreos/etcd/third_party/github.com/gorilla/mux"
-)
-
-// Watches a given key prefix for changes.
-func WatchKeyHandler(w http.ResponseWriter, req *http.Request, s Server) error {
-	var err error
-	vars := mux.Vars(req)
-	key := "/" + vars["key"]
-
-	// Create a command to watch from a given index (default 0).
-	var sinceIndex uint64 = 0
-	if req.Method == "POST" {
-		sinceIndex, err = strconv.ParseUint(string(req.FormValue("index")), 10, 64)
-		if err != nil {
-			return etcdErr.NewError(203, "Watch From Index", s.Store().Index())
-		}
-	}
-
-	// Start the watcher on the store.
-	watcher, err := s.Store().Watch(key, false, false, sinceIndex)
-	if err != nil {
-		return etcdErr.NewError(500, key, s.Store().Index())
-	}
-	event := <-watcher.EventChan
-
-	// Convert event to a response and write to client.
-	w.WriteHeader(http.StatusOK)
-	if req.Method == "HEAD" {
-		return nil
-	}
-	b, _ := json.Marshal(event.Response(s.Store().Index()))
-	w.Write(b)
-	return nil
-}

+ 0 - 51
store/event.go

@@ -45,54 +45,3 @@ func (e *Event) IsCreated() bool {
 func (e *Event) Index() uint64 {
 	return e.Node.ModifiedIndex
 }
-
-// Converts an event object into a response object.
-func (event *Event) Response(currentIndex uint64) interface{} {
-	if !event.Node.Dir {
-		response := &Response{
-			Action:     event.Action,
-			Key:        event.Node.Key,
-			Value:      event.Node.Value,
-			Index:      event.Node.ModifiedIndex,
-			TTL:        event.Node.TTL,
-			Expiration: event.Node.Expiration,
-		}
-
-		if event.PrevNode != nil {
-			response.PrevValue = event.PrevNode.Value
-		}
-
-		if currentIndex != 0 {
-			response.Index = currentIndex
-		}
-
-		if response.Action == Set {
-			if response.PrevValue == nil {
-				response.NewKey = true
-			}
-		}
-
-		if response.Action == CompareAndSwap || response.Action == Create {
-			response.Action = "testAndSet"
-		}
-
-		return response
-	} else {
-		responses := make([]*Response, len(event.Node.Nodes))
-
-		for i, node := range event.Node.Nodes {
-			responses[i] = &Response{
-				Action: event.Action,
-				Key:    node.Key,
-				Value:  node.Value,
-				Dir:    node.Dir,
-				Index:  node.ModifiedIndex,
-			}
-
-			if currentIndex != 0 {
-				responses[i].Index = currentIndex
-			}
-		}
-		return responses
-	}
-}

+ 0 - 26
store/response_v1.go

@@ -1,26 +0,0 @@
-package store
-
-import (
-	"time"
-)
-
-// The response from the store to the user who issue a command
-type Response struct {
-	Action    string  `json:"action"`
-	Key       string  `json:"key"`
-	Dir       bool    `json:"dir,omitempty"`
-	PrevValue *string `json:"prevValue,omitempty"`
-	Value     *string `json:"value,omitempty"`
-
-	// If the key did not exist before the action,
-	// this field should be set to true
-	NewKey bool `json:"newKey,omitempty"`
-
-	Expiration *time.Time `json:"expiration,omitempty"`
-
-	// Time to live in second
-	TTL int64 `json:"ttl,omitempty"`
-
-	// The command index of the raft machine when the command is executed
-	Index uint64 `json:"index"`
-}

+ 0 - 3
test.sh

@@ -17,9 +17,6 @@ go test -v ./server -race
 go test -i ./config
 go test -v ./config -race
 
-go test -i ./server/v1/tests
-go test -v ./server/v1/tests -race
-
 go test -i ./server/v2/tests
 go test -v ./server/v2/tests -race
 

+ 0 - 15
tests/fixtures/v1.cluster/README

@@ -1,15 +0,0 @@
-README
-
-The scripts in this directory should be run from the project root:
-
-$ cd $GOPATH/src/github.com/coreos/etcd
-$ tests/fixtures/v1/run.1.sh
-
-Scripts with numbers should be run in separate terminal windows (in order):
-
-$ tests/fixtures/v1/run.1.sh
-$ tests/fixtures/v1/run.2.sh
-$ tests/fixtures/v1/run.3.sh
-$ tests/fixtures/v1/run.4.sh
-
-The resulting server state data can be found in tmp/node*.

+ 0 - 1
tests/fixtures/v1.cluster/node0/conf

@@ -1 +0,0 @@
-{"commitIndex":15,"peers":[{"name":"node2","connectionString":""}]}

+ 0 - 18
tests/fixtures/v1.cluster/node0/info

@@ -1,18 +0,0 @@
-{
- "name": "node0",
- "raftURL": "http://127.0.0.1:7001",
- "etcdURL": "http://127.0.0.1:4001",
- "webURL": "",
- "raftListenHost": "127.0.0.1:7001",
- "etcdListenHost": "127.0.0.1:4001",
- "raftTLS": {
-  "CertFile": "",
-  "KeyFile": "",
-  "CAFile": ""
- },
- "etcdTLS": {
-  "CertFile": "",
-  "KeyFile": "",
-  "CAFile": ""
- }
-}

BIN
tests/fixtures/v1.cluster/node0/log


+ 0 - 1
tests/fixtures/v1.cluster/node2/conf

@@ -1 +0,0 @@
-{"commitIndex":15,"peers":[{"name":"node0","connectionString":""}]}

+ 0 - 18
tests/fixtures/v1.cluster/node2/info

@@ -1,18 +0,0 @@
-{
- "name": "node2",
- "raftURL": "http://127.0.0.1:7002",
- "etcdURL": "http://127.0.0.1:4002",
- "webURL": "",
- "raftListenHost": "127.0.0.1:7002",
- "etcdListenHost": "127.0.0.1:4002",
- "raftTLS": {
-  "CertFile": "",
-  "KeyFile": "",
-  "CAFile": ""
- },
- "etcdTLS": {
-  "CertFile": "",
-  "KeyFile": "",
-  "CAFile": ""
- }
-}

BIN
tests/fixtures/v1.cluster/node2/log


+ 0 - 1
tests/fixtures/v1.cluster/node3/conf

@@ -1 +0,0 @@
-{"commitIndex":15,"peers":[{"name":"node0","connectionString":""},{"name":"node2","connectionString":""}]}

+ 0 - 18
tests/fixtures/v1.cluster/node3/info

@@ -1,18 +0,0 @@
-{
- "name": "node3",
- "raftURL": "http://127.0.0.1:7003",
- "etcdURL": "http://127.0.0.1:4003",
- "webURL": "",
- "raftListenHost": "127.0.0.1:7003",
- "etcdListenHost": "127.0.0.1:4003",
- "raftTLS": {
-  "CertFile": "",
-  "KeyFile": "",
-  "CAFile": ""
- },
- "etcdTLS": {
-  "CertFile": "",
-  "KeyFile": "",
-  "CAFile": ""
- }
-}

BIN
tests/fixtures/v1.cluster/node3/log


+ 0 - 4
tests/fixtures/v1.cluster/run.1.sh

@@ -1,4 +0,0 @@
-#!/bin/sh
-
-./build
-./etcd -d tmp/node0 -n node0

+ 0 - 3
tests/fixtures/v1.cluster/run.2.sh

@@ -1,3 +0,0 @@
-#!/bin/sh
-
-./etcd -s 127.0.0.1:7002 -c 127.0.0.1:4002 -C 127.0.0.1:7001 -d tmp/node2 -n node2

+ 0 - 3
tests/fixtures/v1.cluster/run.3.sh

@@ -1,3 +0,0 @@
-#!/bin/sh
-
-./etcd -s 127.0.0.1:7003 -c 127.0.0.1:4003 -C 127.0.0.1:7001 -d tmp/node3 -n node3

+ 0 - 13
tests/fixtures/v1.cluster/run.4.sh

@@ -1,13 +0,0 @@
-#!/bin/sh
-
-curl -L http://127.0.0.1:4001/v1/keys/message -d value="Hello world"
-curl -L http://127.0.0.1:4001/v1/keys/message -d value="Hello etcd"
-curl -L http://127.0.0.1:4001/v1/keys/message -X DELETE
-curl -L http://127.0.0.1:4001/v1/keys/message2 -d value="Hola"
-curl -L http://127.0.0.1:4001/v1/keys/expiring -d value=bar -d ttl=5
-curl -L http://127.0.0.1:4001/v1/keys/foo -d value=one
-curl -L http://127.0.0.1:4001/v1/keys/foo -d prevValue=two -d value=three
-curl -L http://127.0.0.1:4001/v1/keys/foo -d prevValue=one -d value=two
-curl -L http://127.0.0.1:4001/v1/keys/bar -d prevValue= -d value=four
-curl -L http://127.0.0.1:4001/v1/keys/bar -d prevValue= -d value=five
-curl -X DELETE http://127.0.0.1:7001/remove/node2

+ 0 - 13
tests/fixtures/v1.solo/README

@@ -1,13 +0,0 @@
-README
-
-The scripts in this directory should be run from the project root:
-
-$ cd $GOPATH/src/github.com/coreos/etcd
-$ tests/fixtures/v1.solo/run.1.sh
-
-Scripts with numbers should be run in separate terminal windows (in order):
-
-$ tests/fixtures/v1/run.1.sh
-$ tests/fixtures/v1/run.2.sh
-
-The resulting server state data can be found in tmp/node0.

+ 0 - 1
tests/fixtures/v1.solo/node0/conf

@@ -1 +0,0 @@
-{"commitIndex":1,"peers":[]}

+ 0 - 18
tests/fixtures/v1.solo/node0/info

@@ -1,18 +0,0 @@
-{
- "name": "node0",
- "raftURL": "http://127.0.0.1:7001",
- "etcdURL": "http://127.0.0.1:4001",
- "webURL": "",
- "raftListenHost": "127.0.0.1:7001",
- "etcdListenHost": "127.0.0.1:4001",
- "raftTLS": {
-  "CertFile": "",
-  "KeyFile": "",
-  "CAFile": ""
- },
- "etcdTLS": {
-  "CertFile": "",
-  "KeyFile": "",
-  "CAFile": ""
- }
-}

BIN
tests/fixtures/v1.solo/node0/log


+ 0 - 4
tests/fixtures/v1.solo/run.1.sh

@@ -1,4 +0,0 @@
-#!/bin/sh
-
-./build
-./etcd -d tmp/node0 -n node0

+ 0 - 3
tests/fixtures/v1.solo/run.2.sh

@@ -1,3 +0,0 @@
-#!/bin/sh
-
-curl -L http://127.0.0.1:4001/v1/keys/message -d value="Hello world"

+ 1 - 1
tests/functional/util.go

@@ -227,7 +227,7 @@ func Monitor(size int, allowDeadNum int, leaderChan chan string, all chan bool,
 
 func getLeader(addr string) (string, error) {
 
-	resp, err := client.Get(addr + "/v1/leader")
+	resp, err := client.Get(addr + "/v2/leader")
 
 	if err != nil {
 		return "", err

+ 0 - 106
tests/functional/v1_migration_test.go

@@ -1,106 +0,0 @@
-package test
-
-import (
-	"fmt"
-	"io/ioutil"
-	"net/http"
-	"os"
-	"os/exec"
-	"path/filepath"
-	"testing"
-	"time"
-
-	"github.com/coreos/etcd/tests"
-	"github.com/coreos/etcd/third_party/github.com/stretchr/testify/assert"
-)
-
-// Ensure that we can start a v2 node from the log of a v1 node.
-func TestV1SoloMigration(t *testing.T) {
-	path, _ := ioutil.TempDir("", "etcd-")
-	os.MkdirAll(path, 0777)
-	defer os.RemoveAll(path)
-
-	nodepath := filepath.Join(path, "node0")
-	fixturepath, _ := filepath.Abs("../fixtures/v1.solo/node0")
-	fmt.Println("DATA_DIR =", nodepath)
-
-	// Copy over fixture files.
-	c := exec.Command("cp", "-rf", fixturepath, nodepath)
-	if out, err := c.CombinedOutput(); err != nil {
-		fmt.Println(">>>>>>\n", string(out), "<<<<<<")
-		panic("Fixture initialization error:" + err.Error())
-	}
-
-	procAttr := new(os.ProcAttr)
-	procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr}
-
-	args := []string{"etcd", fmt.Sprintf("-data-dir=%s", nodepath)}
-	args = append(args, "-addr", "127.0.0.1:4001")
-	args = append(args, "-peer-addr", "127.0.0.1:7001")
-	args = append(args, "-name", "node0")
-	process, err := os.StartProcess(EtcdBinPath, args, procAttr)
-	if err != nil {
-		t.Fatal("start process failed:" + err.Error())
-		return
-	}
-	defer process.Kill()
-	time.Sleep(time.Second)
-
-	// Ensure deleted message is removed.
-	resp, err := tests.Get("http://localhost:4001/v2/keys/message")
-	tests.ReadBody(resp)
-	assert.Nil(t, err, "")
-	assert.Equal(t, resp.StatusCode, 200, "")
-}
-
-// Ensure that we can start a v2 cluster from the logs of a v1 cluster.
-func TestV1ClusterMigration(t *testing.T) {
-	path, _ := ioutil.TempDir("", "etcd-")
-	os.RemoveAll(path)
-	defer os.RemoveAll(path)
-
-	nodes := []string{"node0", "node2"}
-	for i, node := range nodes {
-		nodepath := filepath.Join(path, node)
-		fixturepath, _ := filepath.Abs(filepath.Join("../fixtures/v1.cluster/", node))
-		fmt.Println("FIXPATH  =", fixturepath)
-		fmt.Println("NODEPATH =", nodepath)
-		os.MkdirAll(filepath.Dir(nodepath), 0777)
-
-		// Copy over fixture files.
-		c := exec.Command("cp", "-rf", fixturepath, nodepath)
-		if out, err := c.CombinedOutput(); err != nil {
-			fmt.Println(">>>>>>\n", string(out), "<<<<<<")
-			panic("Fixture initialization error:" + err.Error())
-		}
-
-		procAttr := new(os.ProcAttr)
-		procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr}
-
-		args := []string{"etcd", fmt.Sprintf("-data-dir=%s", nodepath)}
-		args = append(args, "-addr", fmt.Sprintf("127.0.0.1:%d", 4001+i))
-		args = append(args, "-peer-addr", fmt.Sprintf("127.0.0.1:%d", 7001+i))
-		args = append(args, "-name", node)
-		process, err := os.StartProcess(EtcdBinPath, args, procAttr)
-		if err != nil {
-			t.Fatal("start process failed:" + err.Error())
-			return
-		}
-		defer process.Kill()
-		time.Sleep(time.Second)
-	}
-
-	// Ensure deleted message is removed.
-	resp, err := tests.Get("http://localhost:4001/v2/keys/message")
-	body := tests.ReadBody(resp)
-	assert.Nil(t, err, "")
-	assert.Equal(t, resp.StatusCode, http.StatusNotFound)
-	assert.Equal(t, string(body), `{"errorCode":100,"message":"Key not found","cause":"/message","index":11}`+"\n")
-
-	// Ensure TTL'd message is removed.
-	resp, err = tests.Get("http://localhost:4001/v2/keys/foo")
-	body = tests.ReadBody(resp)
-	assert.Nil(t, err, "")
-	assert.Equal(t, resp.StatusCode, 200, "")
-	assert.Equal(t, string(body), `{"action":"get","node":{"key":"/foo","value":"one","modifiedIndex":9,"createdIndex":9}}`)
-}