Skip to content

Commit

Permalink
Merge pull request kubernetes#3384 from derekwaynecarr/list_watch_by_…
Browse files Browse the repository at this point in the history
…namespace

Add ability to listwatch a resource in an optional namespace
  • Loading branch information
lavalamp committed Jan 13, 2015
2 parents bb140d6 + 7c630fd commit 224a8d6
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 6 deletions.
3 changes: 3 additions & 0 deletions pkg/client/cache/listwatch.go
Original file line number Diff line number Diff line change
Expand Up @@ -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().
Expand All @@ -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).
Expand Down
66 changes: 60 additions & 6 deletions pkg/client/cache/listwatch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -34,29 +37,70 @@ 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
lw ListWatch
}{
// Minion
{
location: "/api/" + testapi.Version() + "/minions",
location: buildLocation(buildResourcePath("", api.NamespaceAll, "minions"), buildQueryValues(api.NamespaceAll, nil)),
lw: ListWatch{
FieldSelector: parseSelectorOrDie(""),
Resource: "minions",
},
},
// 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,
Expand All @@ -80,15 +124,15 @@ 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(""),
Resource: "minions",
},
},
{
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(""),
Expand All @@ -97,11 +141,21 @@ 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",
},
},
}
Expand Down

0 comments on commit 224a8d6

Please sign in to comment.