Browse Source

Use go-etcd release-0.4 branch

go-etcd master branch is for etcd 2.0. This patch
vendors in the 0.4 branch. The patch to go-etcd's master
branch that closed idle connections has already been
cherry-picked onto 0.4 branch.
Eugene Yakubovich 10 years ago
parent
commit
f12b662e42
19 changed files with 109 additions and 1108 deletions
  1. 3 13
      Godeps/Godeps.json
  2. 0 21
      Godeps/_workspace/src/github.com/coreos/etcd/etcdserver/etcdhttp/httptypes/doc.go
  3. 0 51
      Godeps/_workspace/src/github.com/coreos/etcd/etcdserver/etcdhttp/httptypes/errors.go
  4. 0 49
      Godeps/_workspace/src/github.com/coreos/etcd/etcdserver/etcdhttp/httptypes/errors_test.go
  5. 0 101
      Godeps/_workspace/src/github.com/coreos/etcd/etcdserver/etcdhttp/httptypes/member.go
  6. 0 220
      Godeps/_workspace/src/github.com/coreos/etcd/etcdserver/etcdhttp/httptypes/member_test.go
  7. 0 43
      Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/id.go
  8. 0 96
      Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/id_test.go
  9. 0 180
      Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/set.go
  10. 0 166
      Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/set_test.go
  11. 0 24
      Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/slice.go
  12. 0 76
      Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/urls.go
  13. 23 36
      Godeps/_workspace/src/github.com/coreos/go-etcd/etcd/client.go
  14. 3 3
      Godeps/_workspace/src/github.com/coreos/go-etcd/etcd/client_test.go
  15. 25 8
      Godeps/_workspace/src/github.com/coreos/go-etcd/etcd/cluster.go
  16. 0 5
      Godeps/_workspace/src/github.com/coreos/go-etcd/etcd/get.go
  17. 5 5
      Godeps/_workspace/src/github.com/coreos/go-etcd/etcd/options.go
  18. 47 8
      Godeps/_workspace/src/github.com/coreos/go-etcd/etcd/requests.go
  19. 3 3
      Godeps/_workspace/src/github.com/coreos/go-etcd/etcd/set_curl_chan_test.go

+ 3 - 13
Godeps/Godeps.json

@@ -1,24 +1,14 @@
 {
 	"ImportPath": "github.com/coreos/flannel",
-	"GoVersion": "go1.3.1",
+	"GoVersion": "go1.4.2",
 	"Packages": [
 		"./..."
 	],
 	"Deps": [
-		{
-			"ImportPath": "github.com/coreos/etcd/etcdserver/etcdhttp/httptypes",
-			"Comment": "v2.0.0-rc.1-135-g945c5dd",
-			"Rev": "945c5dd5588240407e09329bca9314b66220b9ff"
-		},
-		{
-			"ImportPath": "github.com/coreos/etcd/pkg/types",
-			"Comment": "v2.0.0-rc.1-135-g945c5dd",
-			"Rev": "945c5dd5588240407e09329bca9314b66220b9ff"
-		},
 		{
 			"ImportPath": "github.com/coreos/go-etcd/etcd",
-			"Comment": "v0.4.6-12-gbf30eb7",
-			"Rev": "bf30eb7162940ff9aa35d55b23e49ba69322963d"
+			"Comment": "v0.4.6-3-g441f1a1",
+			"Rev": "441f1a1a60ef3f700b6f4b4099e0c35527a25031"
 		},
 		{
 			"ImportPath": "github.com/coreos/go-systemd/daemon",

+ 0 - 21
Godeps/_workspace/src/github.com/coreos/etcd/etcdserver/etcdhttp/httptypes/doc.go

@@ -1,21 +0,0 @@
-/*
-   Copyright 2014 CoreOS, Inc.
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-*/
-
-/*
-Package httptypes defines how etcd's HTTP API entities are serialized to and deserialized from JSON.
-*/
-
-package httptypes

+ 0 - 51
Godeps/_workspace/src/github.com/coreos/etcd/etcdserver/etcdhttp/httptypes/errors.go

@@ -1,51 +0,0 @@
-/*
-   Copyright 2014 CoreOS, Inc.
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-*/
-
-package httptypes
-
-import (
-	"encoding/json"
-	"log"
-	"net/http"
-)
-
-type HTTPError struct {
-	Message string `json:"message"`
-	// HTTP return code
-	Code int `json:"-"`
-}
-
-func (e HTTPError) Error() string {
-	return e.Message
-}
-
-// TODO(xiangli): handle http write errors
-func (e HTTPError) WriteTo(w http.ResponseWriter) {
-	w.Header().Set("Content-Type", "application/json")
-	w.WriteHeader(e.Code)
-	b, err := json.Marshal(e)
-	if err != nil {
-		log.Panicf("marshal HTTPError should never fail: %v", err)
-	}
-	w.Write(b)
-}
-
-func NewHTTPError(code int, m string) *HTTPError {
-	return &HTTPError{
-		Message: m,
-		Code:    code,
-	}
-}

+ 0 - 49
Godeps/_workspace/src/github.com/coreos/etcd/etcdserver/etcdhttp/httptypes/errors_test.go

@@ -1,49 +0,0 @@
-/*
-   Copyright 2014 CoreOS, Inc.
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-*/
-
-package httptypes
-
-import (
-	"net/http"
-	"net/http/httptest"
-	"reflect"
-	"testing"
-)
-
-func TestHTTPErrorWriteTo(t *testing.T) {
-	err := NewHTTPError(http.StatusBadRequest, "what a bad request you made!")
-	rr := httptest.NewRecorder()
-	err.WriteTo(rr)
-
-	wcode := http.StatusBadRequest
-	wheader := http.Header(map[string][]string{
-		"Content-Type": []string{"application/json"},
-	})
-	wbody := `{"message":"what a bad request you made!"}`
-
-	if wcode != rr.Code {
-		t.Errorf("HTTP status code %d, want %d", rr.Code, wcode)
-	}
-
-	if !reflect.DeepEqual(wheader, rr.HeaderMap) {
-		t.Errorf("HTTP headers %v, want %v", rr.HeaderMap, wheader)
-	}
-
-	gbody := rr.Body.String()
-	if wbody != gbody {
-		t.Errorf("HTTP body %q, want %q", gbody, wbody)
-	}
-}

+ 0 - 101
Godeps/_workspace/src/github.com/coreos/etcd/etcdserver/etcdhttp/httptypes/member.go

@@ -1,101 +0,0 @@
-/*
-   Copyright 2014 CoreOS, Inc.
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-*/
-
-package httptypes
-
-import (
-	"encoding/json"
-
-	"github.com/coreos/flannel/Godeps/_workspace/src/github.com/coreos/etcd/pkg/types"
-)
-
-type Member struct {
-	ID         string   `json:"id"`
-	Name       string   `json:"name"`
-	PeerURLs   []string `json:"peerURLs"`
-	ClientURLs []string `json:"clientURLs"`
-}
-
-type MemberCreateRequest struct {
-	PeerURLs types.URLs
-}
-
-type MemberUpdateRequest struct {
-	MemberCreateRequest
-}
-
-func (m *MemberCreateRequest) MarshalJSON() ([]byte, error) {
-	s := struct {
-		PeerURLs []string `json:"peerURLs"`
-	}{
-		PeerURLs: make([]string, len(m.PeerURLs)),
-	}
-
-	for i, u := range m.PeerURLs {
-		s.PeerURLs[i] = u.String()
-	}
-
-	return json.Marshal(&s)
-}
-
-func (m *MemberCreateRequest) UnmarshalJSON(data []byte) error {
-	s := struct {
-		PeerURLs []string `json:"peerURLs"`
-	}{}
-
-	err := json.Unmarshal(data, &s)
-	if err != nil {
-		return err
-	}
-
-	urls, err := types.NewURLs(s.PeerURLs)
-	if err != nil {
-		return err
-	}
-
-	m.PeerURLs = urls
-	return nil
-}
-
-type MemberCollection []Member
-
-func (c *MemberCollection) MarshalJSON() ([]byte, error) {
-	d := struct {
-		Members []Member `json:"members"`
-	}{
-		Members: []Member(*c),
-	}
-
-	return json.Marshal(d)
-}
-
-func (c *MemberCollection) UnmarshalJSON(data []byte) error {
-	d := struct {
-		Members []Member
-	}{}
-
-	if err := json.Unmarshal(data, &d); err != nil {
-		return err
-	}
-
-	if d.Members == nil {
-		*c = make([]Member, 0)
-		return nil
-	}
-
-	*c = d.Members
-	return nil
-}

+ 0 - 220
Godeps/_workspace/src/github.com/coreos/etcd/etcdserver/etcdhttp/httptypes/member_test.go

@@ -1,220 +0,0 @@
-/*
-   Copyright 2014 CoreOS, Inc.
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-*/
-
-package httptypes
-
-import (
-	"encoding/json"
-	"net/url"
-	"reflect"
-	"testing"
-
-	"github.com/coreos/etcd/pkg/types"
-)
-
-func TestMemberUnmarshal(t *testing.T) {
-	tests := []struct {
-		body       []byte
-		wantMember Member
-		wantError  bool
-	}{
-		// no URLs, just check ID & Name
-		{
-			body:       []byte(`{"id": "c", "name": "dungarees"}`),
-			wantMember: Member{ID: "c", Name: "dungarees", PeerURLs: nil, ClientURLs: nil},
-		},
-
-		// both client and peer URLs
-		{
-			body: []byte(`{"peerURLs": ["http://127.0.0.1:4001"], "clientURLs": ["http://127.0.0.1:4001"]}`),
-			wantMember: Member{
-				PeerURLs: []string{
-					"http://127.0.0.1:4001",
-				},
-				ClientURLs: []string{
-					"http://127.0.0.1:4001",
-				},
-			},
-		},
-
-		// multiple peer URLs
-		{
-			body: []byte(`{"peerURLs": ["http://127.0.0.1:4001", "https://example.com"]}`),
-			wantMember: Member{
-				PeerURLs: []string{
-					"http://127.0.0.1:4001",
-					"https://example.com",
-				},
-				ClientURLs: nil,
-			},
-		},
-
-		// multiple client URLs
-		{
-			body: []byte(`{"clientURLs": ["http://127.0.0.1:4001", "https://example.com"]}`),
-			wantMember: Member{
-				PeerURLs: nil,
-				ClientURLs: []string{
-					"http://127.0.0.1:4001",
-					"https://example.com",
-				},
-			},
-		},
-
-		// invalid JSON
-		{
-			body:      []byte(`{"peerU`),
-			wantError: true,
-		},
-	}
-
-	for i, tt := range tests {
-		got := Member{}
-		err := json.Unmarshal(tt.body, &got)
-		if tt.wantError != (err != nil) {
-			t.Errorf("#%d: want error %t, got %v", i, tt.wantError, err)
-			continue
-		}
-
-		if !reflect.DeepEqual(tt.wantMember, got) {
-			t.Errorf("#%d: incorrect output: want=%#v, got=%#v", i, tt.wantMember, got)
-		}
-	}
-}
-
-func TestMemberCollectionUnmarshal(t *testing.T) {
-	tests := []struct {
-		body []byte
-		want MemberCollection
-	}{
-		{
-			body: []byte(`{"members":[]}`),
-			want: MemberCollection([]Member{}),
-		},
-		{
-			body: []byte(`{"members":[{"id":"2745e2525fce8fe","peerURLs":["http://127.0.0.1:7003"],"name":"node3","clientURLs":["http://127.0.0.1:4003"]},{"id":"42134f434382925","peerURLs":["http://127.0.0.1:2380","http://127.0.0.1:7001"],"name":"node1","clientURLs":["http://127.0.0.1:2379","http://127.0.0.1:4001"]},{"id":"94088180e21eb87b","peerURLs":["http://127.0.0.1:7002"],"name":"node2","clientURLs":["http://127.0.0.1:4002"]}]}`),
-			want: MemberCollection(
-				[]Member{
-					{
-						ID:   "2745e2525fce8fe",
-						Name: "node3",
-						PeerURLs: []string{
-							"http://127.0.0.1:7003",
-						},
-						ClientURLs: []string{
-							"http://127.0.0.1:4003",
-						},
-					},
-					{
-						ID:   "42134f434382925",
-						Name: "node1",
-						PeerURLs: []string{
-							"http://127.0.0.1:2380",
-							"http://127.0.0.1:7001",
-						},
-						ClientURLs: []string{
-							"http://127.0.0.1:2379",
-							"http://127.0.0.1:4001",
-						},
-					},
-					{
-						ID:   "94088180e21eb87b",
-						Name: "node2",
-						PeerURLs: []string{
-							"http://127.0.0.1:7002",
-						},
-						ClientURLs: []string{
-							"http://127.0.0.1:4002",
-						},
-					},
-				},
-			),
-		},
-	}
-
-	for i, tt := range tests {
-		var got MemberCollection
-		err := json.Unmarshal(tt.body, &got)
-		if err != nil {
-			t.Errorf("#%d: unexpected error: %v", i, err)
-			continue
-		}
-
-		if !reflect.DeepEqual(tt.want, got) {
-			t.Errorf("#%d: incorrect output: want=%#v, got=%#v", i, tt.want, got)
-		}
-	}
-}
-
-func TestMemberCreateRequestUnmarshal(t *testing.T) {
-	body := []byte(`{"peerURLs": ["http://127.0.0.1:8081", "https://127.0.0.1:8080"]}`)
-	want := MemberCreateRequest{
-		PeerURLs: types.URLs([]url.URL{
-			url.URL{Scheme: "http", Host: "127.0.0.1:8081"},
-			url.URL{Scheme: "https", Host: "127.0.0.1:8080"},
-		}),
-	}
-
-	var req MemberCreateRequest
-	if err := json.Unmarshal(body, &req); err != nil {
-		t.Fatalf("Unmarshal returned unexpected err=%v", err)
-	}
-
-	if !reflect.DeepEqual(want, req) {
-		t.Fatalf("Failed to unmarshal MemberCreateRequest: want=%#v, got=%#v", want, req)
-	}
-}
-
-func TestMemberCreateRequestUnmarshalFail(t *testing.T) {
-	tests := [][]byte{
-		// invalid JSON
-		[]byte(``),
-		[]byte(`{`),
-
-		// spot-check validation done in types.NewURLs
-		[]byte(`{"peerURLs": "foo"}`),
-		[]byte(`{"peerURLs": ["."]}`),
-		[]byte(`{"peerURLs": []}`),
-		[]byte(`{"peerURLs": ["http://127.0.0.1:4001/foo"]}`),
-		[]byte(`{"peerURLs": ["http://127.0.0.1"]}`),
-	}
-
-	for i, tt := range tests {
-		var req MemberCreateRequest
-		if err := json.Unmarshal(tt, &req); err == nil {
-			t.Errorf("#%d: expected err, got nil", i)
-		}
-	}
-}
-
-func TestMemberCreateRequestMarshal(t *testing.T) {
-	req := MemberCreateRequest{
-		PeerURLs: types.URLs([]url.URL{
-			url.URL{Scheme: "http", Host: "127.0.0.1:8081"},
-			url.URL{Scheme: "https", Host: "127.0.0.1:8080"},
-		}),
-	}
-	want := []byte(`{"peerURLs":["http://127.0.0.1:8081","https://127.0.0.1:8080"]}`)
-
-	got, err := json.Marshal(&req)
-	if err != nil {
-		t.Fatalf("Marshal returned unexpected err=%v", err)
-	}
-
-	if !reflect.DeepEqual(want, got) {
-		t.Fatalf("Failed to marshal MemberCreateRequest: want=%s, got=%s", want, got)
-	}
-}

+ 0 - 43
Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/id.go

@@ -1,43 +0,0 @@
-/*
-   Copyright 2014 CoreOS, Inc.
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-*/
-
-package types
-
-import (
-	"strconv"
-)
-
-// ID represents a generic identifier which is canonically
-// stored as a uint64 but is typically represented as a
-// base-16 string for input/output
-type ID uint64
-
-func (i ID) String() string {
-	return strconv.FormatUint(uint64(i), 16)
-}
-
-// IDFromString attempts to create an ID from a base-16 string.
-func IDFromString(s string) (ID, error) {
-	i, err := strconv.ParseUint(s, 16, 64)
-	return ID(i), err
-}
-
-// IDSlice implements the sort interface
-type IDSlice []ID
-
-func (p IDSlice) Len() int           { return len(p) }
-func (p IDSlice) Less(i, j int) bool { return uint64(p[i]) < uint64(p[j]) }
-func (p IDSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }

+ 0 - 96
Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/id_test.go

@@ -1,96 +0,0 @@
-/*
-   Copyright 2014 CoreOS, Inc.
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-*/
-package types
-
-import (
-	"reflect"
-	"sort"
-	"testing"
-)
-
-func TestIDString(t *testing.T) {
-	tests := []struct {
-		input ID
-		want  string
-	}{
-		{
-			input: 12,
-			want:  "c",
-		},
-		{
-			input: 4918257920282737594,
-			want:  "444129853c343bba",
-		},
-	}
-
-	for i, tt := range tests {
-		got := tt.input.String()
-		if tt.want != got {
-			t.Errorf("#%d: ID.String failure: want=%v, got=%v", i, tt.want, got)
-		}
-	}
-}
-
-func TestIDFromString(t *testing.T) {
-	tests := []struct {
-		input string
-		want  ID
-	}{
-		{
-			input: "17",
-			want:  23,
-		},
-		{
-			input: "612840dae127353",
-			want:  437557308098245459,
-		},
-	}
-
-	for i, tt := range tests {
-		got, err := IDFromString(tt.input)
-		if err != nil {
-			t.Errorf("#%d: IDFromString failure: err=%v", i, err)
-			continue
-		}
-		if tt.want != got {
-			t.Errorf("#%d: IDFromString failure: want=%v, got=%v", i, tt.want, got)
-		}
-	}
-}
-
-func TestIDFromStringFail(t *testing.T) {
-	tests := []string{
-		"",
-		"XXX",
-		"612840dae127353612840dae127353",
-	}
-
-	for i, tt := range tests {
-		_, err := IDFromString(tt)
-		if err == nil {
-			t.Fatalf("#%d: IDFromString expected error, but err=nil", i)
-		}
-	}
-}
-
-func TestIDSlice(t *testing.T) {
-	g := []ID{10, 500, 5, 1, 100, 25}
-	w := []ID{1, 5, 10, 25, 100, 500}
-	sort.Sort(IDSlice(g))
-	if !reflect.DeepEqual(g, w) {
-		t.Errorf("slice after sort = %#v, want %#v", g, w)
-	}
-}

+ 0 - 180
Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/set.go

@@ -1,180 +0,0 @@
-/*
-   Copyright 2014 CoreOS, Inc.
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-*/
-
-package types
-
-import (
-	"reflect"
-	"sort"
-	"sync"
-)
-
-type Set interface {
-	Add(string)
-	Remove(string)
-	Contains(string) bool
-	Equals(Set) bool
-	Length() int
-	Values() []string
-	Copy() Set
-	Sub(Set) Set
-}
-
-func NewUnsafeSet(values ...string) *unsafeSet {
-	set := &unsafeSet{make(map[string]struct{})}
-	for _, v := range values {
-		set.Add(v)
-	}
-	return set
-}
-
-func NewThreadsafeSet(values ...string) *tsafeSet {
-	us := NewUnsafeSet(values...)
-	return &tsafeSet{us, sync.RWMutex{}}
-}
-
-type unsafeSet struct {
-	d map[string]struct{}
-}
-
-// Add adds a new value to the set (no-op if the value is already present)
-func (us *unsafeSet) Add(value string) {
-	us.d[value] = struct{}{}
-}
-
-// Remove removes the given value from the set
-func (us *unsafeSet) Remove(value string) {
-	delete(us.d, value)
-}
-
-// Contains returns whether the set contains the given value
-func (us *unsafeSet) Contains(value string) (exists bool) {
-	_, exists = us.d[value]
-	return
-}
-
-// ContainsAll returns whether the set contains all given values
-func (us *unsafeSet) ContainsAll(values []string) bool {
-	for _, s := range values {
-		if !us.Contains(s) {
-			return false
-		}
-	}
-	return true
-}
-
-// Equals returns whether the contents of two sets are identical
-func (us *unsafeSet) Equals(other Set) bool {
-	v1 := sort.StringSlice(us.Values())
-	v2 := sort.StringSlice(other.Values())
-	v1.Sort()
-	v2.Sort()
-	return reflect.DeepEqual(v1, v2)
-}
-
-// Length returns the number of elements in the set
-func (us *unsafeSet) Length() int {
-	return len(us.d)
-}
-
-// Values returns the values of the Set in an unspecified order.
-func (us *unsafeSet) Values() (values []string) {
-	values = make([]string, 0)
-	for val, _ := range us.d {
-		values = append(values, val)
-	}
-	return
-}
-
-// Copy creates a new Set containing the values of the first
-func (us *unsafeSet) Copy() Set {
-	cp := NewUnsafeSet()
-	for val, _ := range us.d {
-		cp.Add(val)
-	}
-
-	return cp
-}
-
-// Sub removes all elements in other from the set
-func (us *unsafeSet) Sub(other Set) Set {
-	oValues := other.Values()
-	result := us.Copy().(*unsafeSet)
-
-	for _, val := range oValues {
-		if _, ok := result.d[val]; !ok {
-			continue
-		}
-		delete(result.d, val)
-	}
-
-	return result
-}
-
-type tsafeSet struct {
-	us *unsafeSet
-	m  sync.RWMutex
-}
-
-func (ts *tsafeSet) Add(value string) {
-	ts.m.Lock()
-	defer ts.m.Unlock()
-	ts.us.Add(value)
-}
-
-func (ts *tsafeSet) Remove(value string) {
-	ts.m.Lock()
-	defer ts.m.Unlock()
-	ts.us.Remove(value)
-}
-
-func (ts *tsafeSet) Contains(value string) (exists bool) {
-	ts.m.RLock()
-	defer ts.m.RUnlock()
-	return ts.us.Contains(value)
-}
-
-func (ts *tsafeSet) Equals(other Set) bool {
-	ts.m.RLock()
-	defer ts.m.RUnlock()
-	return ts.us.Equals(other)
-}
-
-func (ts *tsafeSet) Length() int {
-	ts.m.RLock()
-	defer ts.m.RUnlock()
-	return ts.us.Length()
-}
-
-func (ts *tsafeSet) Values() (values []string) {
-	ts.m.RLock()
-	defer ts.m.RUnlock()
-	return ts.us.Values()
-}
-
-func (ts *tsafeSet) Copy() Set {
-	ts.m.RLock()
-	defer ts.m.RUnlock()
-	usResult := ts.us.Copy().(*unsafeSet)
-	return &tsafeSet{usResult, sync.RWMutex{}}
-}
-
-func (ts *tsafeSet) Sub(other Set) Set {
-	ts.m.RLock()
-	defer ts.m.RUnlock()
-	usResult := ts.us.Sub(other).(*unsafeSet)
-	return &tsafeSet{usResult, sync.RWMutex{}}
-}

+ 0 - 166
Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/set_test.go

@@ -1,166 +0,0 @@
-/*
-   Copyright 2014 CoreOS, Inc.
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-*/
-
-package types
-
-import (
-	"reflect"
-	"sort"
-	"testing"
-)
-
-func TestUnsafeSet(t *testing.T) {
-	driveSetTests(t, NewUnsafeSet())
-}
-
-func TestThreadsafeSet(t *testing.T) {
-	driveSetTests(t, NewThreadsafeSet())
-}
-
-// Check that two slices contents are equal; order is irrelevant
-func equal(a, b []string) bool {
-	as := sort.StringSlice(a)
-	bs := sort.StringSlice(b)
-	as.Sort()
-	bs.Sort()
-	return reflect.DeepEqual(as, bs)
-}
-
-func driveSetTests(t *testing.T, s Set) {
-	// Verify operations on an empty set
-	eValues := []string{}
-	values := s.Values()
-	if !reflect.DeepEqual(values, eValues) {
-		t.Fatalf("Expect values=%v got %v", eValues, values)
-	}
-	if l := s.Length(); l != 0 {
-		t.Fatalf("Expected length=0, got %d", l)
-	}
-	for _, v := range []string{"foo", "bar", "baz"} {
-		if s.Contains(v) {
-			t.Fatalf("Expect s.Contains(%q) to be fale, got true", v)
-		}
-	}
-
-	// Add three items, ensure they show up
-	s.Add("foo")
-	s.Add("bar")
-	s.Add("baz")
-
-	eValues = []string{"foo", "bar", "baz"}
-	values = s.Values()
-	if !equal(values, eValues) {
-		t.Fatalf("Expect values=%v got %v", eValues, values)
-	}
-
-	for _, v := range eValues {
-		if !s.Contains(v) {
-			t.Fatalf("Expect s.Contains(%q) to be true, got false", v)
-		}
-	}
-
-	if l := s.Length(); l != 3 {
-		t.Fatalf("Expected length=3, got %d", l)
-	}
-
-	// Add the same item a second time, ensuring it is not duplicated
-	s.Add("foo")
-
-	values = s.Values()
-	if !equal(values, eValues) {
-		t.Fatalf("Expect values=%v got %v", eValues, values)
-	}
-	if l := s.Length(); l != 3 {
-		t.Fatalf("Expected length=3, got %d", l)
-	}
-
-	// Remove all items, ensure they are gone
-	s.Remove("foo")
-	s.Remove("bar")
-	s.Remove("baz")
-
-	eValues = []string{}
-	values = s.Values()
-	if !equal(values, eValues) {
-		t.Fatalf("Expect values=%v got %v", eValues, values)
-	}
-
-	if l := s.Length(); l != 0 {
-		t.Fatalf("Expected length=0, got %d", l)
-	}
-
-	// Create new copies of the set, and ensure they are unlinked to the
-	// original Set by making modifications
-	s.Add("foo")
-	s.Add("bar")
-	cp1 := s.Copy()
-	cp2 := s.Copy()
-	s.Remove("foo")
-	cp3 := s.Copy()
-	cp1.Add("baz")
-
-	for i, tt := range []struct {
-		want []string
-		got  []string
-	}{
-		{[]string{"bar"}, s.Values()},
-		{[]string{"foo", "bar", "baz"}, cp1.Values()},
-		{[]string{"foo", "bar"}, cp2.Values()},
-		{[]string{"bar"}, cp3.Values()},
-	} {
-		if !equal(tt.want, tt.got) {
-			t.Fatalf("case %d: expect values=%v got %v", i, tt.want, tt.got)
-		}
-	}
-
-	for i, tt := range []struct {
-		want bool
-		got  bool
-	}{
-		{true, s.Equals(cp3)},
-		{true, cp3.Equals(s)},
-		{false, s.Equals(cp2)},
-		{false, s.Equals(cp1)},
-		{false, cp1.Equals(s)},
-		{false, cp2.Equals(s)},
-		{false, cp2.Equals(cp1)},
-	} {
-		if tt.got != tt.want {
-			t.Fatalf("case %d: want %t, got %t", i, tt.want, tt.got)
-
-		}
-	}
-
-	// Subtract values from a Set, ensuring a new Set is created and
-	// the original Sets are unmodified
-	sub1 := cp1.Sub(s)
-	sub2 := cp2.Sub(cp1)
-
-	for i, tt := range []struct {
-		want []string
-		got  []string
-	}{
-		{[]string{"foo", "bar", "baz"}, cp1.Values()},
-		{[]string{"foo", "bar"}, cp2.Values()},
-		{[]string{"bar"}, s.Values()},
-		{[]string{"foo", "baz"}, sub1.Values()},
-		{[]string{}, sub2.Values()},
-	} {
-		if !equal(tt.want, tt.got) {
-			t.Fatalf("case %d: expect values=%v got %v", i, tt.want, tt.got)
-		}
-	}
-}

+ 0 - 24
Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/slice.go

@@ -1,24 +0,0 @@
-/*
-   Copyright 2014 CoreOS, Inc.
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-*/
-
-package types
-
-// Uint64Slice implements sort interface
-type Uint64Slice []uint64
-
-func (p Uint64Slice) Len() int           { return len(p) }
-func (p Uint64Slice) Less(i, j int) bool { return p[i] < p[j] }
-func (p Uint64Slice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }

+ 0 - 76
Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/urls.go

@@ -1,76 +0,0 @@
-/*
-   Copyright 2014 CoreOS, Inc.
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-*/
-
-package types
-
-import (
-	"errors"
-	"fmt"
-	"net"
-	"net/url"
-	"sort"
-	"strings"
-)
-
-type URLs []url.URL
-
-func (us URLs) String() string {
-	return strings.Join(us.StringSlice(), ",")
-}
-
-func (us *URLs) Sort() {
-	sort.Sort(us)
-}
-func (us URLs) Len() int           { return len(us) }
-func (us URLs) Less(i, j int) bool { return us[i].String() < us[j].String() }
-func (us URLs) Swap(i, j int)      { us[i], us[j] = us[j], us[i] }
-
-func (us URLs) StringSlice() []string {
-	out := make([]string, len(us))
-	for i := range us {
-		out[i] = us[i].String()
-	}
-
-	return out
-}
-
-func NewURLs(strs []string) (URLs, error) {
-	all := make([]url.URL, len(strs))
-	if len(all) == 0 {
-		return nil, errors.New("no valid URLs given")
-	}
-	for i, in := range strs {
-		in = strings.TrimSpace(in)
-		u, err := url.Parse(in)
-		if err != nil {
-			return nil, err
-		}
-		if u.Scheme != "http" && u.Scheme != "https" {
-			return nil, fmt.Errorf("URL scheme must be http or https: %s", in)
-		}
-		if _, _, err := net.SplitHostPort(u.Host); err != nil {
-			return nil, fmt.Errorf(`URL address does not have the form "host:port": %s`, in)
-		}
-		if u.Path != "" {
-			return nil, fmt.Errorf("URL must not contain a path: %s", in)
-		}
-		all[i] = *u
-	}
-	us := URLs(all)
-	us.Sort()
-
-	return us, nil
-}

+ 23 - 36
Godeps/_workspace/src/github.com/coreos/go-etcd/etcd/client.go

@@ -7,16 +7,12 @@ import (
 	"errors"
 	"io"
 	"io/ioutil"
-	"math/rand"
 	"net"
 	"net/http"
 	"net/url"
 	"os"
 	"path"
-	"strings"
 	"time"
-
-	"github.com/coreos/flannel/Godeps/_workspace/src/github.com/coreos/etcd/etcdserver/etcdhttp/httptypes"
 )
 
 // See SetConsistency for how to use these constants.
@@ -32,10 +28,6 @@ const (
 	defaultBufferSize = 10
 )
 
-func init() {
-	rand.Seed(int64(time.Now().Nanosecond()))
-}
-
 type Config struct {
 	CertFile    string        `json:"certFile"`
 	KeyFile     string        `json:"keyFile"`
@@ -73,7 +65,8 @@ func NewClient(machines []string) *Client {
 	config := Config{
 		// default timeout is one second
 		DialTimeout: time.Second,
-		Consistency: WEAK_CONSISTENCY,
+		// default consistency level is STRONG
+		Consistency: STRONG_CONSISTENCY,
 	}
 
 	client := &Client{
@@ -97,7 +90,8 @@ func NewTLSClient(machines []string, cert, key, caCert string) (*Client, error)
 	config := Config{
 		// default timeout is one second
 		DialTimeout: time.Second,
-		Consistency: WEAK_CONSISTENCY,
+		// default consistency level is STRONG
+		Consistency: STRONG_CONSISTENCY,
 		CertFile:    cert,
 		KeyFile:     key,
 		CaCertFile:  make([]string, 0),
@@ -305,37 +299,30 @@ func (c *Client) SyncCluster() bool {
 // internalSyncCluster syncs cluster information using the given machine list.
 func (c *Client) internalSyncCluster(machines []string) bool {
 	for _, machine := range machines {
-		httpPath := c.createHttpPath(machine, path.Join(version, "members"))
+		httpPath := c.createHttpPath(machine, path.Join(version, "machines"))
 		resp, err := c.httpClient.Get(httpPath)
 		if err != nil {
 			// try another machine in the cluster
 			continue
+		} else {
+			b, err := ioutil.ReadAll(resp.Body)
+			resp.Body.Close()
+			if err != nil {
+				// try another machine in the cluster
+				continue
+			}
+
+			// update Machines List
+			c.cluster.updateFromStr(string(b))
+
+			// update leader
+			// the first one in the machine list is the leader
+			c.cluster.switchLeader(0)
+
+			logger.Debug("sync.machines ", c.cluster.Machines)
+			c.saveConfig()
+			return true
 		}
-
-		b, err := ioutil.ReadAll(resp.Body)
-		resp.Body.Close()
-		if err != nil {
-			// try another machine in the cluster
-			continue
-		}
-
-		var mCollection httptypes.MemberCollection
-		if err := json.Unmarshal(b, &mCollection); err != nil {
-			// try another machine
-			continue
-		}
-
-		urls := make([]string, 0)
-		for _, m := range mCollection {
-			urls = append(urls, m.ClientURLs...)
-		}
-
-		// update Machines List
-		c.cluster.updateFromStr(strings.Join(urls, ","))
-
-		logger.Debug("sync.machines ", c.cluster.Machines)
-		c.saveConfig()
-		return true
 	}
 	return false
 }

+ 3 - 3
Godeps/_workspace/src/github.com/coreos/go-etcd/etcd/client_test.go

@@ -10,7 +10,7 @@ import (
 )
 
 // To pass this test, we need to create a cluster of 3 machines
-// The server should be listening on localhost:4001, 4002, 4003
+// The server should be listening on 127.0.0.1:4001, 4002, 4003
 func TestSync(t *testing.T) {
 	fmt.Println("Make sure there are three nodes at 0.0.0.0:4001-4003")
 
@@ -36,8 +36,8 @@ func TestSync(t *testing.T) {
 		if err != nil {
 			t.Fatal(err)
 		}
-		if host != "localhost" {
-			t.Fatal("Host must be localhost")
+		if host != "127.0.0.1" {
+			t.Fatal("Host must be 127.0.0.1")
 		}
 	}
 

+ 25 - 8
Godeps/_workspace/src/github.com/coreos/go-etcd/etcd/cluster.go

@@ -1,14 +1,13 @@
 package etcd
 
 import (
-	"math/rand"
+	"net/url"
 	"strings"
 )
 
 type Cluster struct {
 	Leader   string   `json:"leader"`
 	Machines []string `json:"machines"`
-	picked   int
 }
 
 func NewCluster(machines []string) *Cluster {
@@ -19,16 +18,34 @@ func NewCluster(machines []string) *Cluster {
 
 	// default leader and machines
 	return &Cluster{
-		Leader:   "",
+		Leader:   machines[0],
 		Machines: machines,
-		picked:   rand.Intn(len(machines)),
 	}
 }
 
-func (cl *Cluster) failure()     { cl.picked = rand.Intn(len(cl.Machines)) }
-func (cl *Cluster) pick() string { return cl.Machines[cl.picked] }
+// switchLeader switch the current leader to machines[num]
+func (cl *Cluster) switchLeader(num int) {
+	logger.Debugf("switch.leader[from %v to %v]",
+		cl.Leader, cl.Machines[num])
+
+	cl.Leader = cl.Machines[num]
+}
 
 func (cl *Cluster) updateFromStr(machines string) {
-	cl.Machines = strings.Split(machines, ",")
-	cl.picked = rand.Intn(len(cl.Machines))
+	cl.Machines = strings.Split(machines, ", ")
+}
+
+func (cl *Cluster) updateLeader(leader string) {
+	logger.Debugf("update.leader[%s,%s]", cl.Leader, leader)
+	cl.Leader = leader
+}
+
+func (cl *Cluster) updateLeaderFromURL(u *url.URL) {
+	var leader string
+	if u.Scheme == "" {
+		leader = "http://" + u.Host
+	} else {
+		leader = u.Scheme + "://" + u.Host
+	}
+	cl.updateLeader(leader)
 }

+ 0 - 5
Godeps/_workspace/src/github.com/coreos/go-etcd/etcd/get.go

@@ -18,14 +18,9 @@ func (c *Client) Get(key string, sort, recursive bool) (*Response, error) {
 }
 
 func (c *Client) RawGet(key string, sort, recursive bool) (*RawResponse, error) {
-	var q bool
-	if c.config.Consistency == STRONG_CONSISTENCY {
-		q = true
-	}
 	ops := Options{
 		"recursive": recursive,
 		"sorted":    sort,
-		"quorum":    q,
 	}
 
 	return c.get(key, ops)

+ 5 - 5
Godeps/_workspace/src/github.com/coreos/go-etcd/etcd/options.go

@@ -17,11 +17,11 @@ type validOptions map[string]reflect.Kind
 // values are meant to be used as constants.
 var (
 	VALID_GET_OPTIONS = validOptions{
-		"recursive": reflect.Bool,
-		"quorum":    reflect.Bool,
-		"sorted":    reflect.Bool,
-		"wait":      reflect.Bool,
-		"waitIndex": reflect.Uint64,
+		"recursive":  reflect.Bool,
+		"consistent": reflect.Bool,
+		"sorted":     reflect.Bool,
+		"wait":       reflect.Bool,
+		"waitIndex":  reflect.Uint64,
 	}
 
 	VALID_PUT_OPTIONS = validOptions{

+ 47 - 8
Godeps/_workspace/src/github.com/coreos/go-etcd/etcd/requests.go

@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"io"
 	"io/ioutil"
+	"math/rand"
 	"net"
 	"net/http"
 	"net/url"
@@ -39,9 +40,15 @@ func NewRawRequest(method, relativePath string, values url.Values, cancel <-chan
 // getCancelable issues a cancelable GET request
 func (c *Client) getCancelable(key string, options Options,
 	cancel <-chan bool) (*RawResponse, error) {
-	logger.Debugf("get %s [%s]", key, c.cluster.pick())
+	logger.Debugf("get %s [%s]", key, c.cluster.Leader)
 	p := keyToPath(key)
 
+	// If consistency level is set to STRONG, append
+	// the `consistent` query string.
+	if c.config.Consistency == STRONG_CONSISTENCY {
+		options["consistent"] = true
+	}
+
 	str, err := options.toParameters(VALID_GET_OPTIONS)
 	if err != nil {
 		return nil, err
@@ -67,7 +74,7 @@ func (c *Client) get(key string, options Options) (*RawResponse, error) {
 func (c *Client) put(key string, value string, ttl uint64,
 	options Options) (*RawResponse, error) {
 
-	logger.Debugf("put %s, %s, ttl: %d, [%s]", key, value, ttl, c.cluster.pick())
+	logger.Debugf("put %s, %s, ttl: %d, [%s]", key, value, ttl, c.cluster.Leader)
 	p := keyToPath(key)
 
 	str, err := options.toParameters(VALID_PUT_OPTIONS)
@@ -88,7 +95,7 @@ func (c *Client) put(key string, value string, ttl uint64,
 
 // post issues a POST request
 func (c *Client) post(key string, value string, ttl uint64) (*RawResponse, error) {
-	logger.Debugf("post %s, %s, ttl: %d, [%s]", key, value, ttl, c.cluster.pick())
+	logger.Debugf("post %s, %s, ttl: %d, [%s]", key, value, ttl, c.cluster.Leader)
 	p := keyToPath(key)
 
 	req := NewRawRequest("POST", p, buildValues(value, ttl), nil)
@@ -103,7 +110,7 @@ func (c *Client) post(key string, value string, ttl uint64) (*RawResponse, error
 
 // delete issues a DELETE request
 func (c *Client) delete(key string, options Options) (*RawResponse, error) {
-	logger.Debugf("delete %s [%s]", key, c.cluster.pick())
+	logger.Debugf("delete %s [%s]", key, c.cluster.Leader)
 	p := keyToPath(key)
 
 	str, err := options.toParameters(VALID_DELETE_OPTIONS)
@@ -124,6 +131,7 @@ func (c *Client) delete(key string, options Options) (*RawResponse, error) {
 
 // SendRequest sends a HTTP request and returns a Response as defined by etcd
 func (c *Client) SendRequest(rr *RawRequest) (*RawResponse, error) {
+
 	var req *http.Request
 	var resp *http.Response
 	var httpPath string
@@ -189,7 +197,14 @@ func (c *Client) SendRequest(rr *RawRequest) (*RawResponse, error) {
 
 		logger.Debug("Connecting to etcd: attempt ", attempt+1, " for ", rr.RelativePath)
 
-		httpPath = c.getHttpPath(rr.RelativePath)
+		if rr.Method == "GET" && c.config.Consistency == WEAK_CONSISTENCY {
+			// If it's a GET and consistency level is set to WEAK,
+			// then use a random machine.
+			httpPath = c.getHttpPath(true, rr.RelativePath)
+		} else {
+			// Else use the leader.
+			httpPath = c.getHttpPath(false, rr.RelativePath)
+		}
 
 		// Return a cURL command if curlChan is set
 		if c.cURLch != nil {
@@ -250,7 +265,7 @@ func (c *Client) SendRequest(rr *RawRequest) (*RawResponse, error) {
 				return nil, checkErr
 			}
 
-			c.cluster.failure()
+			c.cluster.switchLeader(attempt % len(c.cluster.Machines))
 			continue
 		}
 
@@ -281,6 +296,22 @@ func (c *Client) SendRequest(rr *RawRequest) (*RawResponse, error) {
 			}
 		}
 
+		// if resp is TemporaryRedirect, set the new leader and retry
+		if resp.StatusCode == http.StatusTemporaryRedirect {
+			u, err := resp.Location()
+
+			if err != nil {
+				logger.Warning(err)
+			} else {
+				// Update cluster leader based on redirect location
+				// because it should point to the leader address
+				c.cluster.updateLeaderFromURL(u)
+				logger.Debug("recv.response.relocate ", u.String())
+			}
+			resp.Body.Close()
+			continue
+		}
+
 		if checkErr := checkRetry(c.cluster, numReqs, *resp,
 			errors.New("Unexpected HTTP status code")); checkErr != nil {
 			return nil, checkErr
@@ -345,11 +376,19 @@ func shouldRetry(r http.Response) bool {
 	return r.StatusCode == http.StatusInternalServerError
 }
 
-func (c *Client) getHttpPath(s ...string) string {
-	fullPath := c.cluster.pick() + "/" + version
+func (c *Client) getHttpPath(random bool, s ...string) string {
+	var machine string
+	if random {
+		machine = c.cluster.Machines[rand.Intn(len(c.cluster.Machines))]
+	} else {
+		machine = c.cluster.Leader
+	}
+
+	fullPath := machine + "/" + version
 	for _, seg := range s {
 		fullPath = fullPath + "/" + seg
 	}
+
 	return fullPath
 }
 

+ 3 - 3
Godeps/_workspace/src/github.com/coreos/go-etcd/etcd/set_curl_chan_test.go

@@ -19,7 +19,7 @@ func TestSetCurlChan(t *testing.T) {
 	}
 
 	expected := fmt.Sprintf("curl -X PUT %s/v2/keys/foo -d value=bar -d ttl=5",
-		c.cluster.pick())
+		c.cluster.Leader)
 	actual := c.RecvCURL()
 	if expected != actual {
 		t.Fatalf(`Command "%s" is not equal to expected value "%s"`,
@@ -32,8 +32,8 @@ func TestSetCurlChan(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	expected = fmt.Sprintf("curl -X GET %s/v2/keys/foo?quorum=true&recursive=false&sorted=false",
-		c.cluster.pick())
+	expected = fmt.Sprintf("curl -X GET %s/v2/keys/foo?consistent=true&recursive=false&sorted=false",
+		c.cluster.Leader)
 	actual = c.RecvCURL()
 	if expected != actual {
 		t.Fatalf(`Command "%s" is not equal to expected value "%s"`,