From 7c630fd797d85cd74814f6c6cfb3c16dc227bf30 Mon Sep 17 00:00:00 2001 From: derekwaynecarr Date: Sat, 10 Jan 2015 01:04:26 -0500 Subject: [PATCH] Add ability to listwatch in namespace --- pkg/client/cache/listwatch.go | 3 ++ pkg/client/cache/listwatch_test.go | 66 +++++++++++++++++++++++++++--- 2 files changed, 63 insertions(+), 6 deletions(-) diff --git a/pkg/client/cache/listwatch.go b/pkg/client/cache/listwatch.go index 39d82d2f028..75ac25d73c4 100644 --- a/pkg/client/cache/listwatch.go +++ b/pkg/client/cache/listwatch.go @@ -29,12 +29,14 @@ type ListWatch struct { Client *client.Client FieldSelector labels.Selector Resource string + Namespace string } // ListWatch knows how to list and watch a set of apiserver resources. func (lw *ListWatch) List() (runtime.Object, error) { return lw.Client. Get(). + Namespace(lw.Namespace). Resource(lw.Resource). SelectorParam("fields", lw.FieldSelector). Do(). @@ -45,6 +47,7 @@ func (lw *ListWatch) Watch(resourceVersion string) (watch.Interface, error) { return lw.Client. Get(). Prefix("watch"). + Namespace(lw.Namespace). Resource(lw.Resource). SelectorParam("fields", lw.FieldSelector). Param("resourceVersion", resourceVersion). diff --git a/pkg/client/cache/listwatch_test.go b/pkg/client/cache/listwatch_test.go index 6741bc3d812..f6395ad3065 100644 --- a/pkg/client/cache/listwatch_test.go +++ b/pkg/client/cache/listwatch_test.go @@ -18,8 +18,11 @@ package cache import ( "net/http/httptest" + "net/url" + "path" "testing" + "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi" "github.com/GoogleCloudPlatform/kubernetes/pkg/client" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" @@ -34,6 +37,39 @@ func parseSelectorOrDie(s string) labels.Selector { return selector } +// buildResourcePath is a convenience function for knowing if a namespace should be in a path param or not +func buildResourcePath(prefix, namespace, resource string) string { + base := path.Join("/api", testapi.Version(), prefix) + if len(namespace) > 0 { + if !(testapi.Version() == "v1beta1" || testapi.Version() == "v1beta2") { + base = path.Join(base, "ns", namespace) + } + } + return path.Join(base, resource) +} + +// buildQueryValues is a convenience function for knowing if a namespace should be in a query param or not +func buildQueryValues(namespace string, query url.Values) url.Values { + v := url.Values{} + if query != nil { + for key, values := range query { + for _, value := range values { + v.Add(key, value) + } + } + } + if len(namespace) > 0 { + if testapi.Version() == "v1beta1" || testapi.Version() == "v1beta2" { + v.Set("namespace", namespace) + } + } + return v +} + +func buildLocation(resourcePath string, query url.Values) string { + return resourcePath + "?" + query.Encode() +} + func TestListWatchesCanList(t *testing.T) { table := []struct { location string @@ -41,7 +77,7 @@ func TestListWatchesCanList(t *testing.T) { }{ // Minion { - location: "/api/" + testapi.Version() + "/minions", + location: buildLocation(buildResourcePath("", api.NamespaceAll, "minions"), buildQueryValues(api.NamespaceAll, nil)), lw: ListWatch{ FieldSelector: parseSelectorOrDie(""), Resource: "minions", @@ -49,14 +85,22 @@ func TestListWatchesCanList(t *testing.T) { }, // pod with "assigned" field selector. { - location: "/api/" + testapi.Version() + "/pods?fields=DesiredState.Host%3D", + location: buildLocation(buildResourcePath("", api.NamespaceAll, "pods"), buildQueryValues(api.NamespaceAll, url.Values{"fields": []string{"DesiredState.Host="}})), lw: ListWatch{ FieldSelector: labels.Set{"DesiredState.Host": ""}.AsSelector(), Resource: "pods", }, }, + // pod in namespace "foo" + { + location: buildLocation(buildResourcePath("", "foo", "pods"), buildQueryValues("foo", url.Values{"fields": []string{"DesiredState.Host="}})), + lw: ListWatch{ + FieldSelector: labels.Set{"DesiredState.Host": ""}.AsSelector(), + Resource: "pods", + Namespace: "foo", + }, + }, } - for _, item := range table { handler := util.FakeHandler{ StatusCode: 500, @@ -80,7 +124,7 @@ func TestListWatchesCanWatch(t *testing.T) { }{ // Minion { - location: "/api/" + testapi.Version() + "/watch/minions?resourceVersion=", + location: buildLocation(buildResourcePath("watch", api.NamespaceAll, "minions"), buildQueryValues(api.NamespaceAll, url.Values{"resourceVersion": []string{""}})), rv: "", lw: ListWatch{ FieldSelector: parseSelectorOrDie(""), @@ -88,7 +132,7 @@ func TestListWatchesCanWatch(t *testing.T) { }, }, { - location: "/api/" + testapi.Version() + "/watch/minions?resourceVersion=42", + location: buildLocation(buildResourcePath("watch", api.NamespaceAll, "minions"), buildQueryValues(api.NamespaceAll, url.Values{"resourceVersion": []string{"42"}})), rv: "42", lw: ListWatch{ FieldSelector: parseSelectorOrDie(""), @@ -97,13 +141,23 @@ func TestListWatchesCanWatch(t *testing.T) { }, // pod with "assigned" field selector. { - location: "/api/" + testapi.Version() + "/watch/pods?fields=DesiredState.Host%3D&resourceVersion=0", + location: buildLocation(buildResourcePath("watch", api.NamespaceAll, "pods"), buildQueryValues(api.NamespaceAll, url.Values{"fields": []string{"DesiredState.Host="}, "resourceVersion": []string{"0"}})), rv: "0", lw: ListWatch{ FieldSelector: labels.Set{"DesiredState.Host": ""}.AsSelector(), Resource: "pods", }, }, + // pod with namespace foo and assigned field selector + { + location: buildLocation(buildResourcePath("watch", "foo", "pods"), buildQueryValues("foo", url.Values{"fields": []string{"DesiredState.Host="}, "resourceVersion": []string{"0"}})), + rv: "0", + lw: ListWatch{ + FieldSelector: labels.Set{"DesiredState.Host": ""}.AsSelector(), + Resource: "pods", + Namespace: "foo", + }, + }, } for _, item := range table {