From 6feaf8ee4ff75d9411a8867edf05ff11c8f5c2ab Mon Sep 17 00:00:00 2001 From: Wojciech Tyczynski Date: Mon, 13 Apr 2015 12:33:37 +0200 Subject: [PATCH] Support List() single-matchers --- pkg/registry/generic/etcd/etcd.go | 17 +++++++++++++--- pkg/registry/generic/etcd/etcd_test.go | 18 +++++++++++++++-- pkg/registry/pod/etcd/etcd_test.go | 9 +++++++++ pkg/tools/etcd_helper.go | 27 ++++++++++++++++++++++++++ 4 files changed, 66 insertions(+), 5 deletions(-) diff --git a/pkg/registry/generic/etcd/etcd.go b/pkg/registry/generic/etcd/etcd.go index b354ad4c160..aa98f392fe4 100644 --- a/pkg/registry/generic/etcd/etcd.go +++ b/pkg/registry/generic/etcd/etcd.go @@ -145,9 +145,20 @@ func (e *Etcd) List(ctx api.Context, label labels.Selector, field fields.Selecto // ListPredicate returns a list of all the items matching m. func (e *Etcd) ListPredicate(ctx api.Context, m generic.Matcher) (runtime.Object, error) { list := e.NewListFunc() - err := e.Helper.ExtractToList(e.KeyRootFunc(ctx), list) - if err != nil { - return nil, err + if name, ok := m.MatchesSingle(); ok { + key, err := e.KeyFunc(ctx, name) + if err != nil { + return nil, err + } + err = e.Helper.ExtractObjToList(key, list) + if err != nil { + return nil, err + } + } else { + err := e.Helper.ExtractToList(e.KeyRootFunc(ctx), list) + if err != nil { + return nil, err + } } return generic.FilterList(list, m, generic.DecoratorFunc(e.Decorator)) } diff --git a/pkg/registry/generic/etcd/etcd_test.go b/pkg/registry/generic/etcd/etcd_test.go index 75f14a7515b..1e586e55637 100644 --- a/pkg/registry/generic/etcd/etcd_test.go +++ b/pkg/registry/generic/etcd/etcd_test.go @@ -126,6 +126,11 @@ func TestEtcdList(t *testing.T) { Spec: api.PodSpec{Host: "machine"}, } + singleElemListResp := &etcd.Response{ + Node: &etcd.Node{ + Value: runtime.EncodeOrDie(testapi.Codec(), podA), + }, + } normalListResp := &etcd.Response{ Node: &etcd.Node{ Nodes: []*etcd.Node{ @@ -174,7 +179,7 @@ func TestEtcdList(t *testing.T) { }, "normalFiltered": { in: tools.EtcdResponseWithError{ - R: normalListResp, + R: singleElemListResp, E: nil, }, m: setMatcher{util.NewStringSet("foo")}, @@ -194,7 +199,16 @@ func TestEtcdList(t *testing.T) { for name, item := range table { fakeClient, registry := NewTestGenericEtcdRegistry(t) - fakeClient.Data[registry.KeyRootFunc(api.NewContext())] = item.in + if name, ok := item.m.MatchesSingle(); ok { + key, err := registry.KeyFunc(api.NewContext(), name) + if err != nil { + t.Errorf("Couldn't create key for %v", name) + continue + } + fakeClient.Data[key] = item.in + } else { + fakeClient.Data[registry.KeyRootFunc(api.NewContext())] = item.in + } list, err := registry.ListPredicate(api.NewContext(), item.m) if e, a := item.succeed, err == nil; e != a { t.Errorf("%v: expected %v, got %v", name, e, a) diff --git a/pkg/registry/pod/etcd/etcd_test.go b/pkg/registry/pod/etcd/etcd_test.go index cdbac4fd460..2611164e8fe 100644 --- a/pkg/registry/pod/etcd/etcd_test.go +++ b/pkg/registry/pod/etcd/etcd_test.go @@ -280,6 +280,15 @@ func TestListPodListSelection(t *testing.T) { }, }, } + fakeEtcdClient.Data["/registry/pods/default/zot"] = tools.EtcdResponseWithError{ + R: &etcd.Response{ + Node: &etcd.Node{ + Value: runtime.EncodeOrDie(latest.Codec, &api.Pod{ + ObjectMeta: api.ObjectMeta{Name: "zot"}, + }), + }, + }, + } storage := NewStorage(helper, nil).Pod ctx := api.NewDefaultContext() diff --git a/pkg/tools/etcd_helper.go b/pkg/tools/etcd_helper.go index 4c5e289d760..c1911bf129b 100644 --- a/pkg/tools/etcd_helper.go +++ b/pkg/tools/etcd_helper.go @@ -151,6 +151,33 @@ func (h *EtcdHelper) ExtractToList(key string, listObj runtime.Object) error { return nil } +// ExtractObjToList unmarshals json found at key and opaques it into a *List api object +// (an object that satisfies the runtime.IsList definition). +func (h *EtcdHelper) ExtractObjToList(key string, listObj runtime.Object) error { + listPtr, err := runtime.GetItemsPtr(listObj) + if err != nil { + return err + } + + response, err := h.Client.Get(key, false, false) + if err != nil && !IsEtcdNotFound(err) { + return err + } + + nodes := make([]*etcd.Node, 0) + nodes = append(nodes, response.Node) + + if err := h.decodeNodeList(nodes, listPtr); err != nil { + return err + } + if h.Versioner != nil { + if err := h.Versioner.UpdateList(listObj, response.EtcdIndex); err != nil { + return err + } + } + return nil +} + // ExtractObj unmarshals json found at key into objPtr. On a not found error, will either return // a zero object of the requested type, or an error, depending on ignoreNotFound. Treats // empty responses and nil response nodes exactly like a not found error.