Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

List objects in deterministic order #3812

Merged
merged 1 commit into from
Jan 27, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion pkg/tools/etcd_tools.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ func etcdErrorIndex(err error) (uint64, bool) {
}

func (h *EtcdHelper) listEtcdNode(key string) ([]*etcd.Node, uint64, error) {
result, err := h.Client.Get(key, false, true)
result, err := h.Client.Get(key, true, true)
if err != nil {
index, ok := etcdErrorIndex(err)
if !ok {
Expand Down
36 changes: 29 additions & 7 deletions pkg/tools/etcd_tools_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,6 @@ import (
"github.com/coreos/go-etcd/etcd"
)

type fakeClientGetSet struct {
get func(key string, sort, recursive bool) (*etcd.Response, error)
set func(key, value string, ttl uint64) (*etcd.Response, error)
}

type TestResource struct {
api.TypeMeta `json:",inline"`
api.ObjectMeta `json:"metadata"`
Expand Down Expand Up @@ -72,17 +67,24 @@ func TestExtractToList(t *testing.T) {
R: &etcd.Response{
EtcdIndex: 10,
Node: &etcd.Node{
Dir: true,
Nodes: []*etcd.Node{
{
Key: "/foo",
Value: `{"id":"foo","kind":"Pod","apiVersion":"v1beta1"}`,
Dir: false,
ModifiedIndex: 1,
},
{
Key: "/bar",
Value: `{"id":"bar","kind":"Pod","apiVersion":"v1beta1"}`,
Dir: false,
ModifiedIndex: 2,
},
{
Key: "/baz",
Value: `{"id":"baz","kind":"Pod","apiVersion":"v1beta1"}`,
Dir: false,
ModifiedIndex: 3,
},
},
Expand All @@ -92,9 +94,10 @@ func TestExtractToList(t *testing.T) {
expect := api.PodList{
ListMeta: api.ListMeta{ResourceVersion: "10"},
Items: []api.Pod{
{ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
// We expect items to be sorted by its name.
{ObjectMeta: api.ObjectMeta{Name: "bar", ResourceVersion: "2"}},
{ObjectMeta: api.ObjectMeta{Name: "baz", ResourceVersion: "3"}},
{ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
},
}

Expand All @@ -116,22 +119,34 @@ func TestExtractToListAcrossDirectories(t *testing.T) {
R: &etcd.Response{
EtcdIndex: 10,
Node: &etcd.Node{
Dir: true,
Nodes: []*etcd.Node{
{
Key: "/directory1",
Value: `{"name": "directory1"}`,
Dir: true,
Nodes: []*etcd.Node{
{
Key: "/foo",
Value: `{"id":"foo","kind":"Pod","apiVersion":"v1beta1"}`,
Dir: false,
ModifiedIndex: 1,
},
{
Key: "/baz",
Value: `{"id":"baz","kind":"Pod","apiVersion":"v1beta1"}`,
Dir: false,
ModifiedIndex: 1,
},
},
},
{
Key: "/directory2",
Value: `{"name": "directory2"}`,
Dir: true,
Nodes: []*etcd.Node{
{
Key: "/bar",
Value: `{"id":"bar","kind":"Pod","apiVersion":"v1beta1"}`,
ModifiedIndex: 2,
},
Expand All @@ -144,6 +159,8 @@ func TestExtractToListAcrossDirectories(t *testing.T) {
expect := api.PodList{
ListMeta: api.ListMeta{ResourceVersion: "10"},
Items: []api.Pod{
// We expect list to be sorted by directory (e.g. namespace) first, then by name.
{ObjectMeta: api.ObjectMeta{Name: "baz", ResourceVersion: "1"}},
{ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
{ObjectMeta: api.ObjectMeta{Name: "bar", ResourceVersion: "2"}},
},
Expand All @@ -166,20 +183,25 @@ func TestExtractToListExcludesDirectories(t *testing.T) {
R: &etcd.Response{
EtcdIndex: 10,
Node: &etcd.Node{
Dir: true,
Nodes: []*etcd.Node{
{
Key: "/foo",
Value: `{"id":"foo","kind":"Pod","apiVersion":"v1beta1"}`,
ModifiedIndex: 1,
},
{
Key: "/bar",
Value: `{"id":"bar","kind":"Pod","apiVersion":"v1beta1"}`,
ModifiedIndex: 2,
},
{
Key: "/baz",
Value: `{"id":"baz","kind":"Pod","apiVersion":"v1beta1"}`,
ModifiedIndex: 3,
},
{
Key: "/directory",
Value: `{"name": "directory"}`,
Dir: true,
},
Expand All @@ -190,9 +212,9 @@ func TestExtractToListExcludesDirectories(t *testing.T) {
expect := api.PodList{
ListMeta: api.ListMeta{ResourceVersion: "10"},
Items: []api.Pod{
{ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
{ObjectMeta: api.ObjectMeta{Name: "bar", ResourceVersion: "2"}},
{ObjectMeta: api.ObjectMeta{Name: "baz", ResourceVersion: "3"}},
{ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
},
}

Expand Down
15 changes: 15 additions & 0 deletions pkg/tools/fake_etcd_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package tools
import (
"errors"
"fmt"
"sort"
"sync"

"github.com/coreos/go-etcd/etcd"
Expand Down Expand Up @@ -132,9 +133,23 @@ func (f *FakeEtcdClient) Get(key string, sort, recursive bool) (*etcd.Response,
return &etcd.Response{}, EtcdErrorNotFound
}
f.t.Logf("returning %v: %#v %#v", key, result.R, result.E)

// Sort response, note this will alter resutl.R.
if result.R.Node != nil && result.R.Node.Nodes != nil && sort {
f.sortResponse(result.R.Node.Nodes)
}
return result.R, result.E
}

func (f *FakeEtcdClient) sortResponse(nodes etcd.Nodes) {
for i := range nodes {
if nodes[i].Dir {
f.sortResponse(nodes[i].Nodes)
}
}
sort.Sort(nodes)
}

func (f *FakeEtcdClient) nodeExists(key string) bool {
result, ok := f.Data[key]
return ok && result.R != nil && result.R.Node != nil && result.E == nil
Expand Down