bump(github.com/coreos/go-etcd): 925b981b19b370a2fe073c2395e8f76cfc241124

This commit is contained in:
Ben Johnson 2013-12-20 15:39:19 -07:00
parent 81a73dbc80
commit 53436af899
11 changed files with 168 additions and 84 deletions

View File

@ -9,7 +9,7 @@ func TestAddChild(t *testing.T) {
c.Delete("nonexistentDir", true)
}()
c.SetDir("fooDir", 5)
c.CreateDir("fooDir", 5)
_, err := c.AddChild("fooDir", "v0", 5)
if err != nil {
@ -44,7 +44,7 @@ func TestAddChildDir(t *testing.T) {
c.Delete("nonexistentDir", true)
}()
c.SetDir("fooDir", 5)
c.CreateDir("fooDir", 5)
_, err := c.AddChildDir("fooDir", 5)
if err != nil {

View File

@ -17,8 +17,7 @@ func TestCompareAndSwap(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if !(resp.Node.Value == "bar2" && resp.Node.PrevValue == "bar" &&
resp.Node.Key == "/foo" && resp.Node.TTL == 5) {
if !(resp.Node.Value == "bar2" && resp.Node.Key == "/foo" && resp.Node.TTL == 5) {
t.Fatalf("CompareAndSwap 1 failed: %#v", resp)
}
@ -38,8 +37,7 @@ func TestCompareAndSwap(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if !(resp.Node.Value == "bar2" && resp.Node.PrevValue == "bar" &&
resp.Node.Key == "/foo" && resp.Node.TTL == 5) {
if !(resp.Node.Value == "bar2" && resp.Node.Key == "/foo" && resp.Node.TTL == 5) {
t.Fatalf("CompareAndSwap 1 failed: %#v", resp)
}

View File

@ -1,14 +1,16 @@
package etcd
// Delete deletes the given key.
// When recursive set to false If the key points to a
// directory, the method will fail.
//
// When recursive set to false, if the key points to a
// directory the method will fail.
//
// When recursive set to true, if the key points to a file,
// the file will be deleted. If the key points
// to a directory, then everything under the directory, including
// all child directories, will be deleted.
// the file will be deleted; if the key points to a directory,
// then everything under the directory (including all child directories)
// will be deleted.
func (c *Client) Delete(key string, recursive bool) (*Response, error) {
raw, err := c.DeleteRaw(key, recursive)
raw, err := c.DeleteRaw(key, recursive, false)
if err != nil {
return nil, err
@ -17,9 +19,21 @@ func (c *Client) Delete(key string, recursive bool) (*Response, error) {
return raw.toResponse()
}
func (c *Client) DeleteRaw(key string, recursive bool) (*RawResponse, error) {
// DeleteDir deletes an empty directory or a key value pair
func (c *Client) DeleteDir(key string) (*Response, error) {
raw, err := c.DeleteRaw(key, false, true)
if err != nil {
return nil, err
}
return raw.toResponse()
}
func (c *Client) DeleteRaw(key string, recursive bool, dir bool) (*RawResponse, error) {
ops := options{
"recursive": recursive,
"dir": dir,
}
return c.delete(key, ops)

View File

@ -16,9 +16,8 @@ func TestDelete(t *testing.T) {
t.Fatal(err)
}
if !(resp.Node.PrevValue == "bar" && resp.Node.Value == "") {
t.Fatalf("Delete failed with %s %s", resp.Node.PrevValue,
resp.Node.Value)
if !(resp.Node.Value == "") {
t.Fatalf("Delete failed with %s", resp.Node.Value)
}
resp, err = c.Delete("foo", false)
@ -36,23 +35,29 @@ func TestDeleteAll(t *testing.T) {
}()
c.Set("foo", "bar", 5)
resp, err := c.Delete("foo", true)
// test delete an empty dir
resp, err := c.DeleteDir("foo")
if err != nil {
t.Fatal(err)
}
if !(resp.Node.PrevValue == "bar" && resp.Node.Value == "") {
if !(resp.Node.Value == "") {
t.Fatalf("DeleteAll 1 failed: %#v", resp)
}
c.SetDir("fooDir", 5)
c.CreateDir("fooDir", 5)
c.Set("fooDir/foo", "bar", 5)
_, err = c.DeleteDir("fooDir")
if err == nil {
t.Fatal("should not able to delete a non-empty dir with deletedir")
}
resp, err = c.Delete("fooDir", true)
if err != nil {
t.Fatal(err)
}
if !(resp.Node.PrevValue == "" && resp.Node.Value == "") {
if !(resp.Node.Value == "") {
t.Fatalf("DeleteAll 2 failed: %#v", resp)
}

View File

@ -5,14 +5,34 @@ import (
"fmt"
)
const (
ErrCodeEtcdNotReachable = 501
)
var (
errorMap = map[int]string{
ErrCodeEtcdNotReachable: "All the given peers are not reachable",
}
)
type EtcdError struct {
ErrorCode int `json:"errorCode"`
Message string `json:"message"`
Cause string `json:"cause,omitempty"`
Index uint64 `json:"index"`
}
func (e EtcdError) Error() string {
return fmt.Sprintf("%d: %s (%s)", e.ErrorCode, e.Message, e.Cause)
return fmt.Sprintf("%v: %v (%v) [%v]", e.ErrorCode, e.Message, e.Cause, e.Index)
}
func newError(errorCode int, cause string, index uint64) *EtcdError {
return &EtcdError{
ErrorCode: errorCode,
Message: errorMap[errorCode],
Cause: cause,
Index: index,
}
}
func handleError(b []byte) error {

View File

@ -35,7 +35,7 @@ func TestGetAll(t *testing.T) {
c.Delete("fooDir", true)
}()
c.SetDir("fooDir", 5)
c.CreateDir("fooDir", 5)
c.Set("fooDir/k0", "v0", 5)
c.Set("fooDir/k1", "v1", 5)
@ -73,7 +73,7 @@ func TestGetAll(t *testing.T) {
}
// Test the `recursive` option
c.SetDir("fooDir/childDir", 5)
c.CreateDir("fooDir/childDir", 5)
c.Set("fooDir/childDir/k2", "v2", 5)
// Return kv-pairs in sorted order
@ -83,6 +83,11 @@ func TestGetAll(t *testing.T) {
result.Node.Expiration = nil
for i, _ := range result.Node.Nodes {
result.Node.Nodes[i].Expiration = nil
if result.Node.Nodes[i].Nodes != nil {
for j, _ := range result.Node.Nodes[i].Nodes {
result.Node.Nodes[i].Nodes[j].Expiration = nil
}
}
}
if err != nil {
@ -95,22 +100,30 @@ func TestGetAll(t *testing.T) {
Dir: true,
Nodes: Nodes{
Node{
Key: "/fooDir/childDir/k2",
Value: "v2",
TTL: 5,
Key: "/fooDir/childDir/k2",
Value: "v2",
TTL: 5,
ModifiedIndex: 34,
CreatedIndex: 34,
},
},
TTL: 5,
TTL: 5,
ModifiedIndex: 33,
CreatedIndex: 33,
},
Node{
Key: "/fooDir/k0",
Value: "v0",
TTL: 5,
Key: "/fooDir/k0",
Value: "v0",
TTL: 5,
ModifiedIndex: 31,
CreatedIndex: 31,
},
Node{
Key: "/fooDir/k1",
Value: "v1",
TTL: 5,
Key: "/fooDir/k1",
Value: "v1",
TTL: 5,
ModifiedIndex: 32,
CreatedIndex: 32,
},
}

View File

@ -28,12 +28,14 @@ var (
"prevValue": reflect.String,
"prevIndex": reflect.Uint64,
"prevExist": reflect.Bool,
"dir": reflect.Bool,
}
VALID_POST_OPTIONS = validOptions{}
VALID_DELETE_OPTIONS = validOptions{
"recursive": reflect.Bool,
"dir": reflect.Bool,
}
)

View File

@ -14,8 +14,8 @@ import (
// get issues a GET request
func (c *Client) get(key string, options options) (*RawResponse, error) {
logger.Debugf("get %s [%s]", key, c.cluster.Leader)
p := keyToPath(key)
p := path.Join("keys", key)
// If consistency level is set to STRONG, append
// the `consistent` query string.
if c.config.Consistency == STRONG_CONSISTENCY {
@ -42,7 +42,7 @@ 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.Leader)
p := path.Join("keys", key)
p := keyToPath(key)
str, err := options.toParameters(VALID_PUT_OPTIONS)
if err != nil {
@ -62,7 +62,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.Leader)
p := path.Join("keys", key)
p := keyToPath(key)
resp, err := c.sendRequest("POST", p, buildValues(value, ttl))
@ -76,8 +76,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.Leader)
p := path.Join("keys", key)
p := keyToPath(key)
str, err := options.toParameters(VALID_DELETE_OPTIONS)
if err != nil {
@ -111,7 +110,8 @@ func (c *Client) sendRequest(method string, relativePath string,
trial++
logger.Debug("begin trail ", trial)
if trial > 2*len(c.cluster.Machines) {
return nil, fmt.Errorf("Cannot reach servers after %v time", trial)
return nil, newError(ErrCodeEtcdNotReachable,
"Tried to connect to each peer twice and failed", 0)
}
if method == "GET" && c.config.Consistency == WEAK_CONSISTENCY {
@ -249,3 +249,19 @@ func buildValues(value string, ttl uint64) url.Values {
return v
}
// convert key string to http path exclude version
// for example: key[foo] -> path[keys/foo]
// key[/] -> path[keys/]
func keyToPath(key string) string {
p := path.Join("keys", key)
// corner case: if key is "/" or "//" ect
// path join will clear the tailing "/"
// we need to add it back
if p == "keys" {
p = "keys/"
}
return p
}

View File

@ -3,6 +3,7 @@ package etcd
import (
"encoding/json"
"net/http"
"strconv"
"time"
)
@ -32,17 +33,24 @@ func (rr *RawResponse) toResponse() (*Response, error) {
return nil, err
}
// attach index and term to response
resp.EtcdIndex, _ = strconv.ParseUint(rr.Header.Get("X-Etcd-Index"), 10, 64)
resp.RaftIndex, _ = strconv.ParseUint(rr.Header.Get("X-Raft-Index"), 10, 64)
resp.RaftTerm, _ = strconv.ParseUint(rr.Header.Get("X-Raft-Term"), 10, 64)
return resp, nil
}
type Response struct {
Action string `json:"action"`
Node *Node `json:"node,omitempty"`
Action string `json:"action"`
Node *Node `json:"node"`
EtcdIndex uint64 `json:"etcdIndex"`
RaftIndex uint64 `json:"raftIndex"`
RaftTerm uint64 `json:"raftTerm"`
}
type Node struct {
Key string `json:"key, omitempty"`
PrevValue string `json:"prevValue,omitempty"`
Value string `json:"value,omitempty"`
Dir bool `json:"dir,omitempty"`
Expiration *time.Time `json:"expiration,omitempty"`

View File

@ -1,6 +1,21 @@
package etcd
// SetDir sets the given key to a directory.
// Set sets the given key to the given value.
// It will create a new key value pair or replace the old one.
// It will not replace a existing directory.
func (c *Client) Set(key string, value string, ttl uint64) (*Response, error) {
raw, err := c.RawSet(key, value, ttl)
if err != nil {
return nil, err
}
return raw.toResponse()
}
// Set sets the given key to a directory.
// It will create a new directory or replace the old key value pair by a directory.
// It will not replace a existing directory.
func (c *Client) SetDir(key string, ttl uint64) (*Response, error) {
raw, err := c.RawSetDir(key, ttl)
@ -11,19 +26,7 @@ func (c *Client) SetDir(key string, ttl uint64) (*Response, error) {
return raw.toResponse()
}
// UpdateDir updates the given key to a directory. It succeeds only if the
// given key already exists.
func (c *Client) UpdateDir(key string, ttl uint64) (*Response, error) {
raw, err := c.RawUpdateDir(key, ttl)
if err != nil {
return nil, err
}
return raw.toResponse()
}
// UpdateDir creates a directory under the given key. It succeeds only if
// CreateDir creates a directory. It succeeds only if
// the given key does not yet exist.
func (c *Client) CreateDir(key string, ttl uint64) (*Response, error) {
raw, err := c.RawCreateDir(key, ttl)
@ -35,21 +38,10 @@ func (c *Client) CreateDir(key string, ttl uint64) (*Response, error) {
return raw.toResponse()
}
// Set sets the given key to the given value.
func (c *Client) Set(key string, value string, ttl uint64) (*Response, error) {
raw, err := c.RawSet(key, value, ttl)
if err != nil {
return nil, err
}
return raw.toResponse()
}
// Update updates the given key to the given value. It succeeds only if the
// UpdateDir updates the given directory. It succeeds only if the
// given key already exists.
func (c *Client) Update(key string, value string, ttl uint64) (*Response, error) {
raw, err := c.RawUpdate(key, value, ttl)
func (c *Client) UpdateDir(key string, ttl uint64) (*Response, error) {
raw, err := c.RawUpdateDir(key, ttl)
if err != nil {
return nil, err
@ -70,13 +62,22 @@ func (c *Client) Create(key string, value string, ttl uint64) (*Response, error)
return raw.toResponse()
}
func (c *Client) RawSetDir(key string, ttl uint64) (*RawResponse, error) {
return c.put(key, "", ttl, nil)
// Update updates the given key to the given value. It succeeds only if the
// given key already exists.
func (c *Client) Update(key string, value string, ttl uint64) (*Response, error) {
raw, err := c.RawUpdate(key, value, ttl)
if err != nil {
return nil, err
}
return raw.toResponse()
}
func (c *Client) RawUpdateDir(key string, ttl uint64) (*RawResponse, error) {
ops := options{
"prevExist": true,
"dir": true,
}
return c.put(key, "", ttl, ops)
@ -85,6 +86,7 @@ func (c *Client) RawUpdateDir(key string, ttl uint64) (*RawResponse, error) {
func (c *Client) RawCreateDir(key string, ttl uint64) (*RawResponse, error) {
ops := options{
"prevExist": false,
"dir": true,
}
return c.put(key, "", ttl, ops)
@ -94,6 +96,14 @@ func (c *Client) RawSet(key string, value string, ttl uint64) (*RawResponse, err
return c.put(key, value, ttl, nil)
}
func (c *Client) RawSetDir(key string, ttl uint64) (*RawResponse, error) {
ops := options{
"dir": true,
}
return c.put(key, "", ttl, ops)
}
func (c *Client) RawUpdate(key string, value string, ttl uint64) (*RawResponse, error) {
ops := options{
"prevExist": true,

View File

@ -22,8 +22,7 @@ func TestSet(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if !(resp.Node.Key == "/foo" && resp.Node.Value == "bar2" &&
resp.Node.PrevValue == "bar" && resp.Node.TTL == 5) {
if !(resp.Node.Key == "/foo" && resp.Node.Value == "bar2" && resp.Node.TTL == 5) {
t.Fatalf("Set 2 failed: %#v", resp)
}
}
@ -47,8 +46,7 @@ func TestUpdate(t *testing.T) {
t.Fatal(err)
}
if !(resp.Action == "update" && resp.Node.Key == "/foo" &&
resp.Node.PrevValue == "bar" && resp.Node.TTL == 5) {
if !(resp.Action == "update" && resp.Node.Key == "/foo" && resp.Node.TTL == 5) {
t.Fatalf("Update 1 failed: %#v", resp)
}
@ -76,7 +74,7 @@ func TestCreate(t *testing.T) {
}
if !(resp.Action == "create" && resp.Node.Key == newKey &&
resp.Node.Value == newValue && resp.Node.PrevValue == "" && resp.Node.TTL == 5) {
resp.Node.Value == newValue && resp.Node.TTL == 5) {
t.Fatalf("Create 1 failed: %#v", resp)
}
@ -95,7 +93,7 @@ func TestSetDir(t *testing.T) {
c.Delete("fooDir", true)
}()
resp, err := c.SetDir("fooDir", 5)
resp, err := c.CreateDir("fooDir", 5)
if err != nil {
t.Fatal(err)
}
@ -104,7 +102,7 @@ func TestSetDir(t *testing.T) {
}
// This should fail because /fooDir already points to a directory
resp, err = c.SetDir("/fooDir", 5)
resp, err = c.CreateDir("/fooDir", 5)
if err == nil {
t.Fatalf("fooDir already points to a directory, so SetDir should have failed."+
"The response was: %#v", resp)
@ -116,12 +114,12 @@ func TestSetDir(t *testing.T) {
}
// This should succeed
// It should replace the key
resp, err = c.SetDir("foo", 5)
if err != nil {
t.Fatal(err)
}
if !(resp.Node.Key == "/foo" && resp.Node.Value == "" &&
resp.Node.PrevValue == "bar" && resp.Node.TTL == 5) {
if !(resp.Node.Key == "/foo" && resp.Node.Value == "" && resp.Node.TTL == 5) {
t.Fatalf("SetDir 2 failed: %#v", resp)
}
}
@ -132,7 +130,7 @@ func TestUpdateDir(t *testing.T) {
c.Delete("fooDir", true)
}()
resp, err := c.SetDir("fooDir", 5)
resp, err := c.CreateDir("fooDir", 5)
if err != nil {
t.Fatal(err)
}
@ -144,7 +142,7 @@ func TestUpdateDir(t *testing.T) {
}
if !(resp.Action == "update" && resp.Node.Key == "/fooDir" &&
resp.Node.Value == "" && resp.Node.PrevValue == "" && resp.Node.TTL == 5) {
resp.Node.Value == "" && resp.Node.TTL == 5) {
t.Fatalf("UpdateDir 1 failed: %#v", resp)
}
@ -169,7 +167,7 @@ func TestCreateDir(t *testing.T) {
}
if !(resp.Action == "create" && resp.Node.Key == "/fooDir" &&
resp.Node.Value == "" && resp.Node.PrevValue == "" && resp.Node.TTL == 5) {
resp.Node.Value == "" && resp.Node.TTL == 5) {
t.Fatalf("CreateDir 1 failed: %#v", resp)
}