Change:
kubectl returns resources in a random order, which makes it hard to look for things when users have a lot resources. Returning resources in deterministic order should be a helpful and trivial change (hopefully). We have an issue about pagination , but that's a larger and separate issue.
We should be cause to not do this on the * namespace - I think thats a special case. No disagreement for other list calls
What is the default etcd response order? Last created or last modified? Sent from my iPhone
I think the order is by key if sort param is given. If not given, the order is by last created (maybe, but we shouldn't trust it). It seems we are not trying to get sorted result from etcd.
Today, I think it's random order in the child key space in etcd (because the node structure uses a map), so you get golang map iteration order without sort. I don't know if sort on server is any cheaper than sort on client today, so we may want to do this in rest / registry rather than by passing etcd.
Apart from performance, sorting in clients means we can also take control of how responses are sorted, so for * namespace, we can sort by namespace, then by resource ID. , Clayton Coleman wrote: Master of Electrical and Computer Engineering Carnegie Mellon University
We can always hint sort to the registry storage layer in the future, so sorting on the client now won't kill us.
Just took a closer look at our rest/registry code to implement the sort (in client), but implementation-wise, it seems much easier to pass sort to etcd (one line change). Also, namespace is a prefix on resource, so sort across all namespace with etcd key will essentially sort resources by namespace then by Name. If we are to implement sort on client side, we can either: sort package: have each list object, ie.e PodList, ControllerList, implement sort interface. (We won't do this). have ListMeta implement sort interface, if there is a way to find enclosing structs (so we can use items field) have api.Object implement sort interface, verify object is list before sorting. sort algorithm ourself, and do it in rest. Is there other golang or kubernetes idom that I haven't been aware of that can be applied to this use case?
----- Original Message ----- I think sorting it on etcd is fine for now - that's the simplest possible thing that works.
Is there any material perf impact in etcd to enable it? Sent from my iPhone
Probably not material. Can always switch away if necessary
Famous last words :-) Sent from my iPhone
Got my hat ready

Discussion:
} func (h *EtcdHelper) listEtcdNode(key string) ([]*etcd.Node, uint64, error) { <del> result, err := h.Client.Get(key, false, true) </del> <ins> result, err := h.Client.Get(key, true, true) </ins> if err != nil { index, ok := etcdErrorIndex(err) if !ok {

"github.com/coreos/go-etcd/etcd" ) <del> type fakeClientGetSet struct { get func(key string, sort, recursive bool) (*etcd.Response, error) set func(key, value string, ttl uint64) (*etcd.Response, error) } </del> type TestResource struct { api.TypeMeta   `json:",inline"` api.ObjectMeta `json:"metadata"`

R: &etcd.Response{ EtcdIndex: 10, Node: &etcd.Node{ <ins> Dir: true, </ins> Nodes: []*etcd.Node{ { <ins> Key:           "/foo", </ins> Value:         `{"id":"foo","kind":"Pod","apiVersion":"v1beta1"}`, <ins> Dir:           false, </ins> ModifiedIndex: 1, }, { <ins> Key:           "/bar", </ins> Value:         `{"id":"bar","kind":"Pod","apiVersion":"v1beta1"}`, <ins> Dir:           false, </ins> ModifiedIndex: 2, }, { <ins> Key:           "/baz", </ins> Value:         `{"id":"baz","kind":"Pod","apiVersion":"v1beta1"}`, <ins> Dir:           false, </ins> ModifiedIndex: 3, }, },

expect := api.PodList{ ListMeta: api.ListMeta{ResourceVersion: "10"}, Items: []api.Pod{ <del> {ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"}}, </del> <ins> // We expect items to be sorted by its name. </ins> {ObjectMeta: api.ObjectMeta{Name: "bar", ResourceVersion: "2"}}, {ObjectMeta: api.ObjectMeta{Name: "baz", ResourceVersion: "3"}}, <ins> {ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"}}, </ins> }, }

R: &etcd.Response{ EtcdIndex: 10, Node: &etcd.Node{ <ins> Dir: true, </ins> Nodes: []*etcd.Node{ { <ins> Key:   "/directory1", </ins> Value: `{"name": "directory1"}`, Dir:   true, Nodes: []*etcd.Node{ { <ins> Key:           "/foo", </ins> Value:         `{"id":"foo","kind":"Pod","apiVersion":"v1beta1"}`, <ins> Dir:           false, ModifiedIndex: 1, }, { Key:           "/baz", Value:         `{"id":"baz","kind":"Pod","apiVersion":"v1beta1"}`, Dir:           false, </ins> ModifiedIndex: 1, }, }, }, { <ins> Key:   "/directory2", </ins> Value: `{"name": "directory2"}`, Dir:   true, Nodes: []*etcd.Node{ { <ins> Key:           "/bar", </ins> Value:         `{"id":"bar","kind":"Pod","apiVersion":"v1beta1"}`, ModifiedIndex: 2, },

expect := api.PodList{ ListMeta: api.ListMeta{ResourceVersion: "10"}, Items: []api.Pod{ <ins> // We expect list to be sorted by directory (e.g. namespace) first, then by name. {ObjectMeta: api.ObjectMeta{Name: "baz", ResourceVersion: "1"}}, </ins> {ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"}}, {ObjectMeta: api.ObjectMeta{Name: "bar", ResourceVersion: "2"}}, },

R: &etcd.Response{ EtcdIndex: 10, Node: &etcd.Node{ <ins> Dir: true, </ins> Nodes: []*etcd.Node{ { <ins> Key:           "/foo", </ins> Value:         `{"id":"foo","kind":"Pod","apiVersion":"v1beta1"}`, ModifiedIndex: 1, }, { <ins> Key:           "/bar", </ins> Value:         `{"id":"bar","kind":"Pod","apiVersion":"v1beta1"}`, ModifiedIndex: 2, }, { <ins> Key:           "/baz", </ins> Value:         `{"id":"baz","kind":"Pod","apiVersion":"v1beta1"}`, ModifiedIndex: 3, }, { <ins> Key:   "/directory", </ins> Value: `{"name": "directory"}`, Dir:   true, },

expect := api.PodList{ ListMeta: api.ListMeta{ResourceVersion: "10"}, Items: []api.Pod{ <del> {ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"}}, </del> {ObjectMeta: api.ObjectMeta{Name: "bar", ResourceVersion: "2"}}, {ObjectMeta: api.ObjectMeta{Name: "baz", ResourceVersion: "3"}}, <ins> {ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"}}, </ins> }, }

import ( "errors" "fmt" <ins> "sort" </ins> "sync" "github.com/coreos/go-etcd/etcd"

return &etcd.Response{}, EtcdErrorNotFound } f.t.Logf("returning %v: %#v %#v", key, result.R, result.E) <ins> // 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) } </ins> return result.R, result.E } <ins> func (f *FakeEtcdClient) sortResponse(nodes etcd.Nodes) { for i := range nodes { if nodes[i].Dir { f.sortResponse(nodes[i].Nodes) } } sort.Sort(nodes) } </ins> func (f *FakeEtcdClient) nodeExists(key string) bool { result, ok := f.Data[key] return ok && result.R != nil && result.R.Node != nil && result.E == nil