diff --git a/pkg/apiserver/apiserver_test.go b/pkg/apiserver/apiserver_test.go index b486c836071..1990946fc4a 100644 --- a/pkg/apiserver/apiserver_test.go +++ b/pkg/apiserver/apiserver_test.go @@ -34,6 +34,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" apierrs "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" @@ -216,7 +217,7 @@ type SimpleRESTStorage struct { // These are set when Watch is called fakeWatch *watch.FakeWatcher requestedLabelSelector labels.Selector - requestedFieldSelector labels.Selector + requestedFieldSelector fields.Selector requestedResourceVersion string requestedResourceNamespace string @@ -230,7 +231,7 @@ type SimpleRESTStorage struct { injectedFunction func(obj runtime.Object) (returnObj runtime.Object, err error) } -func (storage *SimpleRESTStorage) List(ctx api.Context, label, field labels.Selector) (runtime.Object, error) { +func (storage *SimpleRESTStorage) List(ctx api.Context, label labels.Selector, field fields.Selector) (runtime.Object, error) { storage.checkContext(ctx) result := &SimpleList{ Items: storage.list, @@ -296,7 +297,7 @@ func (storage *SimpleRESTStorage) Update(ctx api.Context, obj runtime.Object) (r } // Implement ResourceWatcher. -func (storage *SimpleRESTStorage) Watch(ctx api.Context, label, field labels.Selector, resourceVersion string) (watch.Interface, error) { +func (storage *SimpleRESTStorage) Watch(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) { storage.checkContext(ctx) storage.requestedLabelSelector = label storage.requestedFieldSelector = field diff --git a/pkg/apiserver/interfaces.go b/pkg/apiserver/interfaces.go index a216e04778a..e6c556a3526 100644 --- a/pkg/apiserver/interfaces.go +++ b/pkg/apiserver/interfaces.go @@ -18,6 +18,7 @@ package apiserver import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" "github.com/GoogleCloudPlatform/kubernetes/pkg/watch" @@ -38,7 +39,7 @@ type RESTLister interface { // This object must be a pointer type for use with Codec.DecodeInto([]byte, runtime.Object) NewList() runtime.Object // List selects resources in the storage which match to the selector. - List(ctx api.Context, label, field labels.Selector) (runtime.Object, error) + List(ctx api.Context, label labels.Selector, field fields.Selector) (runtime.Object, error) } type RESTGetter interface { @@ -100,7 +101,7 @@ type ResourceWatcher interface { // are supported; an error should be returned if 'field' tries to select on a field that // isn't supported. 'resourceVersion' allows for continuing/starting a watch at a // particular version. - Watch(ctx api.Context, label, field labels.Selector, resourceVersion string) (watch.Interface, error) + Watch(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) } // Redirector know how to return a remote resource's location. diff --git a/pkg/apiserver/resthandler.go b/pkg/apiserver/resthandler.go index 0c799a9cb2d..0d924b4ecfb 100644 --- a/pkg/apiserver/resthandler.go +++ b/pkg/apiserver/resthandler.go @@ -26,6 +26,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/admission" "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" @@ -82,7 +83,7 @@ func GetResource(r RESTGetter, ctxFn ContextFunc, namer ScopeNamer, codec runtim } } -func parseSelectorQueryParams(query url.Values, version, apiResource string) (label, field labels.Selector, err error) { +func parseSelectorQueryParams(query url.Values, version, apiResource string) (label labels.Selector, field fields.Selector, err error) { labelString := query.Get("labels") label, err = labels.Parse(labelString) if err != nil { @@ -93,7 +94,7 @@ func parseSelectorQueryParams(query url.Values, version, apiResource string) (la return api.Scheme.ConvertFieldLabel(version, apiResource, label, value) } fieldString := query.Get("fields") - field, err = labels.ParseAndTransformSelector(fieldString, convertToInternalVersionFunc) + field, err = fields.ParseAndTransformSelector(fieldString, convertToInternalVersionFunc) if err != nil { return nil, nil, errors.NewBadRequest(fmt.Sprintf("The 'fields' selector parameter (%s) could not be parsed: %v", fieldString, err)) } diff --git a/pkg/apiserver/watch_test.go b/pkg/apiserver/watch_test.go index 95e4ef1c363..6bfb1302d26 100644 --- a/pkg/apiserver/watch_test.go +++ b/pkg/apiserver/watch_test.go @@ -25,6 +25,7 @@ import ( "testing" "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" "github.com/GoogleCloudPlatform/kubernetes/pkg/watch" @@ -209,7 +210,7 @@ func TestWatchParamParsing(t *testing.T) { for _, item := range table { simpleStorage.requestedLabelSelector = labels.Everything() - simpleStorage.requestedFieldSelector = labels.Everything() + simpleStorage.requestedFieldSelector = fields.Everything() simpleStorage.requestedResourceVersion = "5" // Prove this is set in all cases simpleStorage.requestedResourceNamespace = "" dest.RawQuery = item.rawQuery diff --git a/pkg/client/request.go b/pkg/client/request.go index 3519a76d684..919a35e870f 100644 --- a/pkg/client/request.go +++ b/pkg/client/request.go @@ -31,6 +31,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" @@ -255,20 +256,26 @@ func (r *Request) RequestURI(uri string) *Request { return r } -// ParseSelectorParam parses the given string as a resource label selector. +// ParseSelectorParam parses the given string as a resource selector. // This is a convenience function so you don't have to first check that it's a // validly formatted selector. func (r *Request) ParseSelectorParam(paramName, item string) *Request { if r.err != nil { return r } - var sel labels.Selector + var selector string var err error switch paramName { case "labels": - sel, err = labels.Parse(item) + var lsel labels.Selector + if lsel, err = labels.Parse(item); err == nil { + selector = lsel.String() + } case "fields": - sel, err = labels.ParseSelector(item) + var fsel fields.Selector + if fsel, err = fields.ParseSelector(item); err == nil { + selector = fsel.String() + } default: err = fmt.Errorf("unknown parameter name '%s'", paramName) } @@ -276,7 +283,7 @@ func (r *Request) ParseSelectorParam(paramName, item string) *Request { r.err = err return r } - return r.setParam(paramName, sel.String()) + return r.setParam(paramName, selector) } // SelectorParam adds the given selector as a query parameter with the name paramName. @@ -537,7 +544,6 @@ func (r *Request) DoRaw() ([]byte, error) { if err != nil { return nil, err } - r.resp, err = client.Do(r.req) if err != nil { return nil, err diff --git a/pkg/fields/doc.go b/pkg/fields/doc.go new file mode 100644 index 00000000000..2e5b8bc50e3 --- /dev/null +++ b/pkg/fields/doc.go @@ -0,0 +1,19 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package fields implements a simple field system, parsing and matching +// selectors with sets of fields. +package fields diff --git a/pkg/fields/fields.go b/pkg/fields/fields.go new file mode 100644 index 00000000000..e2a6064655e --- /dev/null +++ b/pkg/fields/fields.go @@ -0,0 +1,62 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package fields + +import ( + "sort" + "strings" +) + +// Fields allows you to present fields independently from their storage. +type Fields interface { + // Has returns whether the provided field exists. + Has(field string) (exists bool) + + // Get returns the value for the provided field. + Get(field string) (value string) +} + +// Set is a map of field:value. It implements Fields. +type Set map[string]string + +// String returns all fields listed as a human readable string. +// Conveniently, exactly the format that ParseSelector takes. +func (ls Set) String() string { + selector := make([]string, 0, len(ls)) + for key, value := range ls { + selector = append(selector, key+"="+value) + } + // Sort for determinism. + sort.StringSlice(selector).Sort() + return strings.Join(selector, ",") +} + +// Has returns whether the provided field exists in the map. +func (ls Set) Has(field string) bool { + _, exists := ls[field] + return exists +} + +// Get returns the value in the map for the provided field. +func (ls Set) Get(field string) string { + return ls[field] +} + +// AsSelector converts fields into a selectors. +func (ls Set) AsSelector() Selector { + return SelectorFromSet(ls) +} diff --git a/pkg/fields/fields_test.go b/pkg/fields/fields_test.go new file mode 100644 index 00000000000..c41c8e9876a --- /dev/null +++ b/pkg/fields/fields_test.go @@ -0,0 +1,57 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package fields + +import ( + "testing" +) + +func matches(t *testing.T, ls Set, want string) { + if ls.String() != want { + t.Errorf("Expected '%s', but got '%s'", want, ls.String()) + } +} + +func TestSetString(t *testing.T) { + matches(t, Set{"x": "y"}, "x=y") + matches(t, Set{"foo": "bar"}, "foo=bar") + matches(t, Set{"foo": "bar", "baz": "qup"}, "baz=qup,foo=bar") +} + +func TestFieldHas(t *testing.T) { + fieldHasTests := []struct { + Ls Fields + Key string + Has bool + }{ + {Set{"x": "y"}, "x", true}, + {Set{"x": ""}, "x", true}, + {Set{"x": "y"}, "foo", false}, + } + for _, lh := range fieldHasTests { + if has := lh.Ls.Has(lh.Key); has != lh.Has { + t.Errorf("%#v.Has(%#v) => %v, expected %v", lh.Ls, lh.Key, has, lh.Has) + } + } +} + +func TestFieldGet(t *testing.T) { + ls := Set{"x": "y"} + if ls.Get("x") != "y" { + t.Errorf("Set.Get is broken") + } +} diff --git a/pkg/fields/selector.go b/pkg/fields/selector.go new file mode 100644 index 00000000000..e0ff0830749 --- /dev/null +++ b/pkg/fields/selector.go @@ -0,0 +1,217 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package fields + +import ( + "fmt" + "sort" + "strings" +) + +// Selector represents a field selector. +type Selector interface { + // Matches returns true if this selector matches the given set of fields. + Matches(Fields) bool + + // Empty returns true if this selector does not restrict the selection space. + Empty() bool + + // RequiresExactMatch allows a caller to introspect whether a given selector + // requires a single specific field to be set, and if so returns the value it + // requires. + RequiresExactMatch(field string) (value string, found bool) + + // String returns a human readable string that represents this selector. + String() string +} + +// Everything returns a selector that matches all fields. +func Everything() Selector { + return andTerm{} +} + +type hasTerm struct { + field, value string +} + +func (t *hasTerm) Matches(ls Fields) bool { + return ls.Get(t.field) == t.value +} + +func (t *hasTerm) Empty() bool { + return false +} + +func (t *hasTerm) RequiresExactMatch(field string) (value string, found bool) { + if t.field == field { + return t.value, true + } + return "", false +} + +func (t *hasTerm) String() string { + return fmt.Sprintf("%v=%v", t.field, t.value) +} + +type notHasTerm struct { + field, value string +} + +func (t *notHasTerm) Matches(ls Fields) bool { + return ls.Get(t.field) != t.value +} + +func (t *notHasTerm) Empty() bool { + return false +} + +func (t *notHasTerm) RequiresExactMatch(field string) (value string, found bool) { + return "", false +} + +func (t *notHasTerm) String() string { + return fmt.Sprintf("%v!=%v", t.field, t.value) +} + +type andTerm []Selector + +func (t andTerm) Matches(ls Fields) bool { + for _, q := range t { + if !q.Matches(ls) { + return false + } + } + return true +} + +func (t andTerm) Empty() bool { + if t == nil { + return true + } + if len([]Selector(t)) == 0 { + return true + } + for i := range t { + if !t[i].Empty() { + return false + } + } + return true +} + +func (t andTerm) RequiresExactMatch(field string) (string, bool) { + if t == nil || len([]Selector(t)) == 0 { + return "", false + } + for i := range t { + if value, found := t[i].RequiresExactMatch(field); found { + return value, found + } + } + return "", false +} + +func (t andTerm) String() string { + var terms []string + for _, q := range t { + terms = append(terms, q.String()) + } + return strings.Join(terms, ",") +} + +// SelectorFromSet returns a Selector which will match exactly the given Set. A +// nil Set is considered equivalent to Everything(). +func SelectorFromSet(ls Set) Selector { + if ls == nil { + return Everything() + } + items := make([]Selector, 0, len(ls)) + for field, value := range ls { + items = append(items, &hasTerm{field: field, value: value}) + } + if len(items) == 1 { + return items[0] + } + return andTerm(items) +} + +// ParseSelector takes a string representing a selector and returns an +// object suitable for matching, or an error. +func ParseSelector(selector string) (Selector, error) { + return parseSelector(selector, + func(lhs, rhs string) (newLhs, newRhs string, err error) { + return lhs, rhs, nil + }) +} + +// Parses the selector and runs them through the given TransformFunc. +func ParseAndTransformSelector(selector string, fn TransformFunc) (Selector, error) { + return parseSelector(selector, fn) +} + +// Function to transform selectors. +type TransformFunc func(field, value string) (newField, newValue string, err error) + +func try(selectorPiece, op string) (lhs, rhs string, ok bool) { + pieces := strings.Split(selectorPiece, op) + if len(pieces) == 2 { + return pieces[0], pieces[1], true + } + return "", "", false +} + +func parseSelector(selector string, fn TransformFunc) (Selector, error) { + parts := strings.Split(selector, ",") + sort.StringSlice(parts).Sort() + var items []Selector + for _, part := range parts { + if part == "" { + continue + } + if lhs, rhs, ok := try(part, "!="); ok { + lhs, rhs, err := fn(lhs, rhs) + if err != nil { + return nil, err + } + items = append(items, ¬HasTerm{field: lhs, value: rhs}) + } else if lhs, rhs, ok := try(part, "=="); ok { + lhs, rhs, err := fn(lhs, rhs) + if err != nil { + return nil, err + } + items = append(items, &hasTerm{field: lhs, value: rhs}) + } else if lhs, rhs, ok := try(part, "="); ok { + lhs, rhs, err := fn(lhs, rhs) + if err != nil { + return nil, err + } + items = append(items, &hasTerm{field: lhs, value: rhs}) + } else { + return nil, fmt.Errorf("invalid selector: '%s'; can't understand '%s'", selector, part) + } + } + if len(items) == 1 { + return items[0], nil + } + return andTerm(items), nil +} + +// OneTermEqualSelector returns an object that matches objects where one field/field equals one value. +// Cannot return an error. +func OneTermEqualSelector(k, v string) Selector { + return &hasTerm{field: k, value: v} +} diff --git a/pkg/fields/selector_test.go b/pkg/fields/selector_test.go new file mode 100644 index 00000000000..56431b740a7 --- /dev/null +++ b/pkg/fields/selector_test.go @@ -0,0 +1,208 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package fields + +import ( + "testing" +) + +func TestSelectorParse(t *testing.T) { + testGoodStrings := []string{ + "x=a,y=b,z=c", + "", + "x!=a,y=b", + } + testBadStrings := []string{ + "x=a||y=b", + "x==a==b", + } + for _, test := range testGoodStrings { + lq, err := ParseSelector(test) + if err != nil { + t.Errorf("%v: error %v (%#v)\n", test, err, err) + } + if test != lq.String() { + t.Errorf("%v restring gave: %v\n", test, lq.String()) + } + } + for _, test := range testBadStrings { + _, err := ParseSelector(test) + if err == nil { + t.Errorf("%v: did not get expected error\n", test) + } + } +} + +func TestDeterministicParse(t *testing.T) { + s1, err := ParseSelector("x=a,a=x") + s2, err2 := ParseSelector("a=x,x=a") + if err != nil || err2 != nil { + t.Errorf("Unexpected parse error") + } + if s1.String() != s2.String() { + t.Errorf("Non-deterministic parse") + } +} + +func expectMatch(t *testing.T, selector string, ls Set) { + lq, err := ParseSelector(selector) + if err != nil { + t.Errorf("Unable to parse %v as a selector\n", selector) + return + } + if !lq.Matches(ls) { + t.Errorf("Wanted %s to match '%s', but it did not.\n", selector, ls) + } +} + +func expectNoMatch(t *testing.T, selector string, ls Set) { + lq, err := ParseSelector(selector) + if err != nil { + t.Errorf("Unable to parse %v as a selector\n", selector) + return + } + if lq.Matches(ls) { + t.Errorf("Wanted '%s' to not match '%s', but it did.", selector, ls) + } +} + +func TestEverything(t *testing.T) { + if !Everything().Matches(Set{"x": "y"}) { + t.Errorf("Nil selector didn't match") + } + if !Everything().Empty() { + t.Errorf("Everything was not empty") + } +} + +func TestSelectorMatches(t *testing.T) { + expectMatch(t, "", Set{"x": "y"}) + expectMatch(t, "x=y", Set{"x": "y"}) + expectMatch(t, "x=y,z=w", Set{"x": "y", "z": "w"}) + expectMatch(t, "x!=y,z!=w", Set{"x": "z", "z": "a"}) + expectMatch(t, "notin=in", Set{"notin": "in"}) // in and notin in exactMatch + expectNoMatch(t, "x=y", Set{"x": "z"}) + expectNoMatch(t, "x=y,z=w", Set{"x": "w", "z": "w"}) + expectNoMatch(t, "x!=y,z!=w", Set{"x": "z", "z": "w"}) + + labelset := Set{ + "foo": "bar", + "baz": "blah", + } + expectMatch(t, "foo=bar", labelset) + expectMatch(t, "baz=blah", labelset) + expectMatch(t, "foo=bar,baz=blah", labelset) + expectNoMatch(t, "foo=blah", labelset) + expectNoMatch(t, "baz=bar", labelset) + expectNoMatch(t, "foo=bar,foobar=bar,baz=blah", labelset) +} + +func TestOneTermEqualSelector(t *testing.T) { + if !OneTermEqualSelector("x", "y").Matches(Set{"x": "y"}) { + t.Errorf("No match when match expected.") + } + if OneTermEqualSelector("x", "y").Matches(Set{"x": "z"}) { + t.Errorf("Match when none expected.") + } +} + +func expectMatchDirect(t *testing.T, selector, ls Set) { + if !SelectorFromSet(selector).Matches(ls) { + t.Errorf("Wanted %s to match '%s', but it did not.\n", selector, ls) + } +} + +func expectNoMatchDirect(t *testing.T, selector, ls Set) { + if SelectorFromSet(selector).Matches(ls) { + t.Errorf("Wanted '%s' to not match '%s', but it did.", selector, ls) + } +} + +func TestSetMatches(t *testing.T) { + labelset := Set{ + "foo": "bar", + "baz": "blah", + } + expectMatchDirect(t, Set{}, labelset) + expectMatchDirect(t, Set{"foo": "bar"}, labelset) + expectMatchDirect(t, Set{"baz": "blah"}, labelset) + expectMatchDirect(t, Set{"foo": "bar", "baz": "blah"}, labelset) + expectNoMatchDirect(t, Set{"foo": "=blah"}, labelset) + expectNoMatchDirect(t, Set{"baz": "=bar"}, labelset) + expectNoMatchDirect(t, Set{"foo": "=bar", "foobar": "bar", "baz": "blah"}, labelset) +} + +func TestNilMapIsValid(t *testing.T) { + selector := Set(nil).AsSelector() + if selector == nil { + t.Errorf("Selector for nil set should be Everything") + } + if !selector.Empty() { + t.Errorf("Selector for nil set should be Empty") + } +} + +func TestSetIsEmpty(t *testing.T) { + if !(Set{}).AsSelector().Empty() { + t.Errorf("Empty set should be empty") + } + if !(andTerm(nil)).Empty() { + t.Errorf("Nil andTerm should be empty") + } + if (&hasTerm{}).Empty() { + t.Errorf("hasTerm should not be empty") + } + if (¬HasTerm{}).Empty() { + t.Errorf("notHasTerm should not be empty") + } + if !(andTerm{andTerm{}}).Empty() { + t.Errorf("Nested andTerm should be empty") + } + if (andTerm{&hasTerm{"a", "b"}}).Empty() { + t.Errorf("Nested andTerm should not be empty") + } +} + +func TestRequiresExactMatch(t *testing.T) { + testCases := map[string]struct { + S Selector + Label string + Value string + Found bool + }{ + "empty set": {Set{}.AsSelector(), "test", "", false}, + "nil andTerm": {andTerm(nil), "test", "", false}, + "empty hasTerm": {&hasTerm{}, "test", "", false}, + "skipped hasTerm": {&hasTerm{"a", "b"}, "test", "", false}, + "valid hasTerm": {&hasTerm{"test", "b"}, "test", "b", true}, + "valid hasTerm no value": {&hasTerm{"test", ""}, "test", "", true}, + "valid notHasTerm": {¬HasTerm{"test", "b"}, "test", "", false}, + "valid notHasTerm no value": {¬HasTerm{"test", ""}, "test", "", false}, + "nested andTerm": {andTerm{andTerm{}}, "test", "", false}, + "nested andTerm matches": {andTerm{&hasTerm{"test", "b"}}, "test", "b", true}, + "andTerm with non-match": {andTerm{&hasTerm{}, &hasTerm{"test", "b"}}, "test", "b", true}, + } + for k, v := range testCases { + value, found := v.S.RequiresExactMatch(v.Label) + if value != v.Value { + t.Errorf("%s: expected value %s, got %s", k, v.Value, value) + } + if found != v.Found { + t.Errorf("%s: expected found %t, got %t", k, v.Found, found) + } + } +} diff --git a/pkg/master/rest_to_nodes.go b/pkg/master/rest_to_nodes.go index 087324749a4..08e0b27fde3 100644 --- a/pkg/master/rest_to_nodes.go +++ b/pkg/master/rest_to_nodes.go @@ -22,6 +22,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver" "github.com/GoogleCloudPlatform/kubernetes/pkg/client" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" ) @@ -64,7 +65,7 @@ func (n *nodeAdaptor) Create(minion *api.Node) (*api.Node, error) { // List lists all the nodes in the cluster. func (n *nodeAdaptor) List() (*api.NodeList, error) { ctx := api.NewContext() - obj, err := n.storage.(apiserver.RESTLister).List(ctx, labels.Everything(), labels.Everything()) + obj, err := n.storage.(apiserver.RESTLister).List(ctx, labels.Everything(), fields.Everything()) if err != nil { return nil, err } diff --git a/pkg/registry/controller/registry.go b/pkg/registry/controller/registry.go index 7ce8eb8e5fe..3dfa8a0d04b 100644 --- a/pkg/registry/controller/registry.go +++ b/pkg/registry/controller/registry.go @@ -18,6 +18,7 @@ package controller import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/watch" ) @@ -25,7 +26,7 @@ import ( // Registry is an interface for things that know how to store ReplicationControllers. type Registry interface { ListControllers(ctx api.Context) (*api.ReplicationControllerList, error) - WatchControllers(ctx api.Context, label, field labels.Selector, resourceVersion string) (watch.Interface, error) + WatchControllers(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) GetController(ctx api.Context, controllerID string) (*api.ReplicationController, error) CreateController(ctx api.Context, controller *api.ReplicationController) (*api.ReplicationController, error) UpdateController(ctx api.Context, controller *api.ReplicationController) (*api.ReplicationController, error) diff --git a/pkg/registry/controller/rest.go b/pkg/registry/controller/rest.go index ef2c2f65422..9984699082f 100644 --- a/pkg/registry/controller/rest.go +++ b/pkg/registry/controller/rest.go @@ -24,6 +24,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation" rc "github.com/GoogleCloudPlatform/kubernetes/pkg/controller" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" "github.com/GoogleCloudPlatform/kubernetes/pkg/watch" @@ -82,7 +83,7 @@ func (rs *REST) Get(ctx api.Context, id string) (runtime.Object, error) { } // List obtains a list of ReplicationControllers that match selector. -func (rs *REST) List(ctx api.Context, label, field labels.Selector) (runtime.Object, error) { +func (rs *REST) List(ctx api.Context, label labels.Selector, field fields.Selector) (runtime.Object, error) { if !field.Empty() { return nil, fmt.Errorf("field selector not supported yet") } @@ -129,7 +130,7 @@ func (rs *REST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, boo // Watch returns ReplicationController events via a watch.Interface. // It implements apiserver.ResourceWatcher. -func (rs *REST) Watch(ctx api.Context, label, field labels.Selector, resourceVersion string) (watch.Interface, error) { +func (rs *REST) Watch(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) { return rs.registry.WatchControllers(ctx, label, field, resourceVersion) } diff --git a/pkg/registry/controller/rest_test.go b/pkg/registry/controller/rest_test.go index 2d31c00994b..2de7bbfbad4 100644 --- a/pkg/registry/controller/rest_test.go +++ b/pkg/registry/controller/rest_test.go @@ -29,6 +29,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest/resttest" _ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest" ) @@ -41,7 +42,7 @@ func TestListControllersError(t *testing.T) { registry: &mockRegistry, } ctx := api.NewContext() - controllers, err := storage.List(ctx, labels.Everything(), labels.Everything()) + controllers, err := storage.List(ctx, labels.Everything(), fields.Everything()) if err != mockRegistry.Err { t.Errorf("Expected %#v, Got %#v", mockRegistry.Err, err) } @@ -58,7 +59,7 @@ func TestListEmptyControllerList(t *testing.T) { registry: &mockRegistry, } ctx := api.NewContext() - controllers, err := storage.List(ctx, labels.Everything(), labels.Everything()) + controllers, err := storage.List(ctx, labels.Everything(), fields.Everything()) if err != nil { t.Errorf("unexpected error: %v", err) } @@ -92,7 +93,7 @@ func TestListControllerList(t *testing.T) { registry: &mockRegistry, } ctx := api.NewContext() - controllersObj, err := storage.List(ctx, labels.Everything(), labels.Everything()) + controllersObj, err := storage.List(ctx, labels.Everything(), fields.Everything()) controllers := controllersObj.(*api.ReplicationControllerList) if err != nil { t.Errorf("unexpected error: %v", err) diff --git a/pkg/registry/endpoint/registry.go b/pkg/registry/endpoint/registry.go index f93d6bed686..c36b023e77f 100644 --- a/pkg/registry/endpoint/registry.go +++ b/pkg/registry/endpoint/registry.go @@ -18,6 +18,7 @@ package endpoint import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/watch" ) @@ -26,6 +27,6 @@ import ( type Registry interface { ListEndpoints(ctx api.Context) (*api.EndpointsList, error) GetEndpoints(ctx api.Context, name string) (*api.Endpoints, error) - WatchEndpoints(ctx api.Context, labels, fields labels.Selector, resourceVersion string) (watch.Interface, error) + WatchEndpoints(ctx api.Context, labels labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) UpdateEndpoints(ctx api.Context, e *api.Endpoints) error } diff --git a/pkg/registry/endpoint/rest.go b/pkg/registry/endpoint/rest.go index 147a9df248c..25f9b473194 100644 --- a/pkg/registry/endpoint/rest.go +++ b/pkg/registry/endpoint/rest.go @@ -21,6 +21,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" "github.com/GoogleCloudPlatform/kubernetes/pkg/watch" @@ -44,7 +45,7 @@ func (rs *REST) Get(ctx api.Context, id string) (runtime.Object, error) { } // List satisfies the RESTStorage interface. -func (rs *REST) List(ctx api.Context, label, field labels.Selector) (runtime.Object, error) { +func (rs *REST) List(ctx api.Context, label labels.Selector, field fields.Selector) (runtime.Object, error) { if !label.Empty() || !field.Empty() { return nil, errors.NewBadRequest("label/field selectors are not supported on endpoints") } @@ -53,7 +54,7 @@ func (rs *REST) List(ctx api.Context, label, field labels.Selector) (runtime.Obj // Watch returns Endpoint events via a watch.Interface. // It implements apiserver.ResourceWatcher. -func (rs *REST) Watch(ctx api.Context, label, field labels.Selector, resourceVersion string) (watch.Interface, error) { +func (rs *REST) Watch(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) { return rs.registry.WatchEndpoints(ctx, label, field, resourceVersion) } diff --git a/pkg/registry/endpoint/rest_test.go b/pkg/registry/endpoint/rest_test.go index 99e00798844..89c33f94882 100644 --- a/pkg/registry/endpoint/rest_test.go +++ b/pkg/registry/endpoint/rest_test.go @@ -22,6 +22,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest" ) @@ -81,7 +82,7 @@ func TestEndpointsRegistryList(t *testing.T) { }, } ctx := api.NewContext() - s, _ := storage.List(ctx, labels.Everything(), labels.Everything()) + s, _ := storage.List(ctx, labels.Everything(), fields.Everything()) sl := s.(*api.EndpointsList) if len(sl.Items) != 2 { t.Fatalf("Expected 2 endpoints, but got %v", len(sl.Items)) diff --git a/pkg/registry/etcd/etcd.go b/pkg/registry/etcd/etcd.go index fced78a806e..479d60f8de5 100644 --- a/pkg/registry/etcd/etcd.go +++ b/pkg/registry/etcd/etcd.go @@ -21,6 +21,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" etcderr "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors/etcd" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/pod" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" @@ -93,7 +94,7 @@ func (r *Registry) ListControllers(ctx api.Context) (*api.ReplicationControllerL } // WatchControllers begins watching for new, changed, or deleted controllers. -func (r *Registry) WatchControllers(ctx api.Context, label, field labels.Selector, resourceVersion string) (watch.Interface, error) { +func (r *Registry) WatchControllers(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) { if !field.Empty() { return nil, fmt.Errorf("field selectors are not supported on replication controllers") } @@ -284,7 +285,7 @@ func (r *Registry) UpdateService(ctx api.Context, svc *api.Service) (*api.Servic } // WatchServices begins watching for new, changed, or deleted service configurations. -func (r *Registry) WatchServices(ctx api.Context, label, field labels.Selector, resourceVersion string) (watch.Interface, error) { +func (r *Registry) WatchServices(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) { version, err := tools.ParseWatchResourceVersion(resourceVersion, "service") if err != nil { return nil, err @@ -329,7 +330,7 @@ func (r *Registry) UpdateEndpoints(ctx api.Context, endpoints *api.Endpoints) er } // WatchEndpoints begins watching for new, changed, or deleted endpoint configurations. -func (r *Registry) WatchEndpoints(ctx api.Context, label, field labels.Selector, resourceVersion string) (watch.Interface, error) { +func (r *Registry) WatchEndpoints(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) { version, err := tools.ParseWatchResourceVersion(resourceVersion, "endpoints") if err != nil { return nil, err @@ -395,7 +396,7 @@ func (r *Registry) DeleteMinion(ctx api.Context, minionID string) error { return nil } -func (r *Registry) WatchMinions(ctx api.Context, label, field labels.Selector, resourceVersion string) (watch.Interface, error) { +func (r *Registry) WatchMinions(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) { version, err := tools.ParseWatchResourceVersion(resourceVersion, "node") if err != nil { return nil, err diff --git a/pkg/registry/etcd/etcd_test.go b/pkg/registry/etcd/etcd_test.go index c07a8257ca5..b9a62f16846 100644 --- a/pkg/registry/etcd/etcd_test.go +++ b/pkg/registry/etcd/etcd_test.go @@ -24,6 +24,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" etcdgeneric "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic/etcd" "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/pod" @@ -281,7 +282,7 @@ func TestEtcdWatchController(t *testing.T) { registry := NewTestEtcdRegistry(fakeClient) watching, err := registry.WatchControllers(ctx, labels.Everything(), - labels.Everything(), + fields.Everything(), "1", ) if err != nil { @@ -310,7 +311,7 @@ func TestEtcdWatchControllersMatch(t *testing.T) { registry := NewTestEtcdRegistryWithPods(fakeClient) watching, err := registry.WatchControllers(ctx, labels.SelectorFromSet(labels.Set{"name": "foo"}), - labels.Everything(), + fields.Everything(), "1", ) if err != nil { @@ -351,7 +352,7 @@ func TestEtcdWatchControllersNotMatch(t *testing.T) { registry := NewTestEtcdRegistryWithPods(fakeClient) watching, err := registry.WatchControllers(ctx, labels.SelectorFromSet(labels.Set{"name": "foo"}), - labels.Everything(), + fields.Everything(), "1", ) if err != nil { @@ -678,7 +679,7 @@ func TestEtcdWatchServices(t *testing.T) { registry := NewTestEtcdRegistry(fakeClient) watching, err := registry.WatchServices(ctx, labels.Everything(), - labels.SelectorFromSet(labels.Set{"name": "foo"}), + fields.SelectorFromSet(fields.Set{"name": "foo"}), "1", ) if err != nil { @@ -707,7 +708,7 @@ func TestEtcdWatchServicesBadSelector(t *testing.T) { _, err := registry.WatchServices( ctx, labels.Everything(), - labels.SelectorFromSet(labels.Set{"Field.Selector": "foo"}), + fields.SelectorFromSet(fields.Set{"Field.Selector": "foo"}), "", ) if err == nil { @@ -717,7 +718,7 @@ func TestEtcdWatchServicesBadSelector(t *testing.T) { _, err = registry.WatchServices( ctx, labels.SelectorFromSet(labels.Set{"Label.Selector": "foo"}), - labels.Everything(), + fields.Everything(), "", ) if err == nil { @@ -732,7 +733,7 @@ func TestEtcdWatchEndpoints(t *testing.T) { watching, err := registry.WatchEndpoints( ctx, labels.Everything(), - labels.SelectorFromSet(labels.Set{"name": "foo"}), + fields.SelectorFromSet(fields.Set{"name": "foo"}), "1", ) if err != nil { @@ -761,7 +762,7 @@ func TestEtcdWatchEndpointsAcrossNamespaces(t *testing.T) { watching, err := registry.WatchEndpoints( ctx, labels.Everything(), - labels.Everything(), + fields.Everything(), "1", ) if err != nil { @@ -790,7 +791,7 @@ func TestEtcdWatchEndpointsBadSelector(t *testing.T) { _, err := registry.WatchEndpoints( ctx, labels.Everything(), - labels.SelectorFromSet(labels.Set{"Field.Selector": "foo"}), + fields.SelectorFromSet(fields.Set{"Field.Selector": "foo"}), "", ) if err == nil { @@ -800,7 +801,7 @@ func TestEtcdWatchEndpointsBadSelector(t *testing.T) { _, err = registry.WatchEndpoints( ctx, labels.SelectorFromSet(labels.Set{"Label.Selector": "foo"}), - labels.Everything(), + fields.Everything(), "", ) if err == nil { @@ -925,7 +926,7 @@ func TestEtcdWatchMinion(t *testing.T) { registry := NewTestEtcdRegistry(fakeClient) watching, err := registry.WatchMinions(ctx, labels.Everything(), - labels.Everything(), + fields.Everything(), "1", ) if err != nil { @@ -953,7 +954,7 @@ func TestEtcdWatchMinionsMatch(t *testing.T) { registry := NewTestEtcdRegistry(fakeClient) watching, err := registry.WatchMinions(ctx, labels.SelectorFromSet(labels.Set{"name": "foo"}), - labels.Everything(), + fields.Everything(), "1", ) if err != nil { @@ -993,7 +994,7 @@ func TestEtcdWatchMinionsNotMatch(t *testing.T) { registry := NewTestEtcdRegistry(fakeClient) watching, err := registry.WatchMinions(ctx, labels.SelectorFromSet(labels.Set{"name": "foo"}), - labels.Everything(), + fields.Everything(), "1", ) if err != nil { diff --git a/pkg/registry/event/rest.go b/pkg/registry/event/rest.go index f4ec1981e00..098d31efb6e 100644 --- a/pkg/registry/event/rest.go +++ b/pkg/registry/event/rest.go @@ -22,6 +22,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" @@ -111,13 +112,13 @@ func (rs *REST) Get(ctx api.Context, id string) (runtime.Object, error) { return event, err } -func (rs *REST) getAttrs(obj runtime.Object) (objLabels, objFields labels.Set, err error) { +func (rs *REST) getAttrs(obj runtime.Object) (objLabels labels.Set, objFields fields.Set, err error) { event, ok := obj.(*api.Event) if !ok { return nil, nil, fmt.Errorf("invalid object type") } // TODO: internal version leaks through here. This should be versioned. - return labels.Set{}, labels.Set{ + return labels.Set{}, fields.Set{ "involvedObject.kind": event.InvolvedObject.Kind, "involvedObject.namespace": event.InvolvedObject.Namespace, "involvedObject.name": event.InvolvedObject.Name, @@ -130,13 +131,13 @@ func (rs *REST) getAttrs(obj runtime.Object) (objLabels, objFields labels.Set, e }, nil } -func (rs *REST) List(ctx api.Context, label, field labels.Selector) (runtime.Object, error) { +func (rs *REST) List(ctx api.Context, label labels.Selector, field fields.Selector) (runtime.Object, error) { return rs.registry.ListPredicate(ctx, &generic.SelectionPredicate{label, field, rs.getAttrs}) } // Watch returns Events events via a watch.Interface. // It implements apiserver.ResourceWatcher. -func (rs *REST) Watch(ctx api.Context, label, field labels.Selector, resourceVersion string) (watch.Interface, error) { +func (rs *REST) Watch(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) { return rs.registry.WatchPredicate(ctx, &generic.SelectionPredicate{label, field, rs.getAttrs}, resourceVersion) } diff --git a/pkg/registry/event/rest_test.go b/pkg/registry/event/rest_test.go index cbcce2fbe11..51e274b63cd 100644 --- a/pkg/registry/event/rest_test.go +++ b/pkg/registry/event/rest_test.go @@ -23,6 +23,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi" "github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" @@ -180,7 +181,7 @@ func TestRESTgetAttrs(t *testing.T) { if e, a := label, (labels.Set{}); !reflect.DeepEqual(e, a) { t.Errorf("diff: %s", util.ObjectDiff(e, a)) } - expect := labels.Set{ + expect := fields.Set{ "involvedObject.kind": "Pod", "involvedObject.name": "foo", "involvedObject.namespace": "baz", @@ -237,7 +238,7 @@ func TestRESTList(t *testing.T) { reg.ObjectList = &api.EventList{ Items: []api.Event{*eventA, *eventB, *eventC}, } - got, err := rest.List(api.NewContext(), labels.Everything(), labels.Set{"source": "GoodSource"}.AsSelector()) + got, err := rest.List(api.NewContext(), labels.Everything(), fields.Set{"source": "GoodSource"}.AsSelector()) if err != nil { t.Fatalf("Unexpected error %v", err) } @@ -262,7 +263,7 @@ func TestRESTWatch(t *testing.T) { Reason: "ForTesting", } reg, rest := NewTestREST() - wi, err := rest.Watch(api.NewContext(), labels.Everything(), labels.Everything(), "0") + wi, err := rest.Watch(api.NewContext(), labels.Everything(), fields.Everything(), "0") if err != nil { t.Fatalf("Unexpected error %v", err) } diff --git a/pkg/registry/generic/etcd/etcd.go b/pkg/registry/generic/etcd/etcd.go index 2ea765fa49a..a746ebd01fb 100644 --- a/pkg/registry/generic/etcd/etcd.go +++ b/pkg/registry/generic/etcd/etcd.go @@ -23,6 +23,7 @@ import ( kubeerr "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" etcderr "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors/etcd" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" @@ -72,7 +73,7 @@ type Etcd struct { TTLFunc func(obj runtime.Object, update bool) (uint64, error) // Returns a matcher corresponding to the provided labels and fields. - PredicateFunc func(label, field labels.Selector) generic.Matcher + PredicateFunc func(label labels.Selector, field fields.Selector) generic.Matcher // Called on all objects returned from the underlying store, after // the exit hooks are invoked. Decorators are intended for integrations @@ -134,7 +135,7 @@ func (e *Etcd) NewList() runtime.Object { } // List returns a list of items matching labels and field -func (e *Etcd) List(ctx api.Context, label, field labels.Selector) (runtime.Object, error) { +func (e *Etcd) List(ctx api.Context, label labels.Selector, field fields.Selector) (runtime.Object, error) { return e.ListPredicate(ctx, e.PredicateFunc(label, field)) } @@ -358,7 +359,7 @@ func (e *Etcd) Delete(ctx api.Context, name string) (runtime.Object, error) { // WatchPredicate starts a watch for the items that m matches. // TODO: Detect if m references a single object instead of a list. -func (e *Etcd) Watch(ctx api.Context, label, field labels.Selector, resourceVersion string) (watch.Interface, error) { +func (e *Etcd) Watch(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) { return e.WatchPredicate(ctx, e.PredicateFunc(label, field), resourceVersion) } diff --git a/pkg/registry/generic/registry.go b/pkg/registry/generic/registry.go index c194208a25d..89a17d9e713 100644 --- a/pkg/registry/generic/registry.go +++ b/pkg/registry/generic/registry.go @@ -18,19 +18,20 @@ package generic import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" "github.com/GoogleCloudPlatform/kubernetes/pkg/watch" ) // AttrFunc returns label and field sets for List or Watch to compare against, or an error. -type AttrFunc func(obj runtime.Object) (label, field labels.Set, err error) +type AttrFunc func(obj runtime.Object) (label labels.Set, field fields.Set, err error) // SelectionPredicate implements a generic predicate that can be passed to // GenericRegistry's List or Watch methods. Implements the Matcher interface. type SelectionPredicate struct { Label labels.Selector - Field labels.Selector + Field fields.Selector GetAttrs AttrFunc } diff --git a/pkg/registry/generic/registry_test.go b/pkg/registry/generic/registry_test.go index e46edf23e80..dc1423b0f77 100644 --- a/pkg/registry/generic/registry_test.go +++ b/pkg/registry/generic/registry_test.go @@ -21,6 +21,7 @@ import ( "reflect" "testing" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" ) @@ -39,7 +40,8 @@ func (*IgnoredList) IsAnAPIObject() {} func TestSelectionPredicate(t *testing.T) { table := map[string]struct { labelSelector, fieldSelector string - labels, fields labels.Set + labels labels.Set + fields fields.Set err error shouldMatch bool }{ @@ -47,21 +49,21 @@ func TestSelectionPredicate(t *testing.T) { labelSelector: "name=foo", fieldSelector: "uid=12345", labels: labels.Set{"name": "foo"}, - fields: labels.Set{"uid": "12345"}, + fields: fields.Set{"uid": "12345"}, shouldMatch: true, }, "B": { labelSelector: "name=foo", fieldSelector: "uid=12345", labels: labels.Set{"name": "foo"}, - fields: labels.Set{}, + fields: fields.Set{}, shouldMatch: false, }, "C": { labelSelector: "name=foo", fieldSelector: "uid=12345", labels: labels.Set{}, - fields: labels.Set{"uid": "12345"}, + fields: fields.Set{"uid": "12345"}, shouldMatch: false, }, "error": { @@ -77,14 +79,14 @@ func TestSelectionPredicate(t *testing.T) { if err != nil { panic(err) } - parsedField, err := labels.ParseSelector(item.fieldSelector) + parsedField, err := fields.ParseSelector(item.fieldSelector) if err != nil { panic(err) } sp := &SelectionPredicate{ Label: parsedLabel, Field: parsedField, - GetAttrs: func(runtime.Object) (label, field labels.Set, err error) { + GetAttrs: func(runtime.Object) (label labels.Set, field fields.Set, err error) { return item.labels, item.fields, item.err }, } diff --git a/pkg/registry/limitrange/rest.go b/pkg/registry/limitrange/rest.go index 7d9bf8c5f58..a76fc6b130c 100644 --- a/pkg/registry/limitrange/rest.go +++ b/pkg/registry/limitrange/rest.go @@ -22,6 +22,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" @@ -130,15 +131,15 @@ func (rs *REST) Get(ctx api.Context, name string) (runtime.Object, error) { return limitRange, err } -func (rs *REST) getAttrs(obj runtime.Object) (objLabels, objFields labels.Set, err error) { - return labels.Set{}, labels.Set{}, nil +func (rs *REST) getAttrs(obj runtime.Object) (objLabels labels.Set, objFields fields.Set, err error) { + return labels.Set{}, fields.Set{}, nil } -func (rs *REST) List(ctx api.Context, label, field labels.Selector) (runtime.Object, error) { +func (rs *REST) List(ctx api.Context, label labels.Selector, field fields.Selector) (runtime.Object, error) { return rs.registry.ListPredicate(ctx, &generic.SelectionPredicate{label, field, rs.getAttrs}) } -func (rs *REST) Watch(ctx api.Context, label, field labels.Selector, resourceVersion string) (watch.Interface, error) { +func (rs *REST) Watch(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) { return rs.registry.WatchPredicate(ctx, &generic.SelectionPredicate{label, field, rs.getAttrs}, resourceVersion) } diff --git a/pkg/registry/minion/registry.go b/pkg/registry/minion/registry.go index c9ce4670d16..94a36f748a8 100644 --- a/pkg/registry/minion/registry.go +++ b/pkg/registry/minion/registry.go @@ -18,6 +18,7 @@ package minion import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/watch" ) @@ -29,5 +30,5 @@ type Registry interface { UpdateMinion(ctx api.Context, minion *api.Node) error GetMinion(ctx api.Context, minionID string) (*api.Node, error) DeleteMinion(ctx api.Context, minionID string) error - WatchMinions(ctx api.Context, label, field labels.Selector, resourceVersion string) (watch.Interface, error) + WatchMinions(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) } diff --git a/pkg/registry/minion/rest.go b/pkg/registry/minion/rest.go index 86f5f6861ef..e93c5aed04c 100644 --- a/pkg/registry/minion/rest.go +++ b/pkg/registry/minion/rest.go @@ -26,6 +26,7 @@ import ( kerrors "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/master/ports" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" @@ -90,7 +91,7 @@ func (rs *REST) Get(ctx api.Context, id string) (runtime.Object, error) { } // List satisfies the RESTStorage interface. -func (rs *REST) List(ctx api.Context, label, field labels.Selector) (runtime.Object, error) { +func (rs *REST) List(ctx api.Context, label labels.Selector, field fields.Selector) (runtime.Object, error) { return rs.registry.ListMinions(ctx) } @@ -134,7 +135,7 @@ func (rs *REST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, boo // Watch returns Minions events via a watch.Interface. // It implements apiserver.ResourceWatcher. -func (rs *REST) Watch(ctx api.Context, label, field labels.Selector, resourceVersion string) (watch.Interface, error) { +func (rs *REST) Watch(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) { return rs.registry.WatchMinions(ctx, label, field, resourceVersion) } diff --git a/pkg/registry/minion/rest_test.go b/pkg/registry/minion/rest_test.go index b6b1e669443..ca10e4a0d40 100644 --- a/pkg/registry/minion/rest_test.go +++ b/pkg/registry/minion/rest_test.go @@ -22,6 +22,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest/resttest" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest" ) @@ -69,7 +70,7 @@ func TestMinionRegistryREST(t *testing.T) { t.Fatalf("delete returned wrong error") } - list, err := ms.List(ctx, labels.Everything(), labels.Everything()) + list, err := ms.List(ctx, labels.Everything(), fields.Everything()) if err != nil { t.Errorf("got error calling List") } diff --git a/pkg/registry/namespace/rest.go b/pkg/registry/namespace/rest.go index db71a3a5cc9..1810b7e0fac 100644 --- a/pkg/registry/namespace/rest.go +++ b/pkg/registry/namespace/rest.go @@ -23,6 +23,7 @@ import ( kerrors "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" @@ -104,15 +105,15 @@ func (rs *REST) Get(ctx api.Context, id string) (runtime.Object, error) { return namespace, err } -func (rs *REST) getAttrs(obj runtime.Object) (objLabels, objFields labels.Set, err error) { - return labels.Set{}, labels.Set{}, nil +func (rs *REST) getAttrs(obj runtime.Object) (objLabels labels.Set, objFields fields.Set, err error) { + return labels.Set{}, fields.Set{}, nil } -func (rs *REST) List(ctx api.Context, label, field labels.Selector) (runtime.Object, error) { +func (rs *REST) List(ctx api.Context, label labels.Selector, field fields.Selector) (runtime.Object, error) { return rs.registry.ListPredicate(ctx, &generic.SelectionPredicate{label, field, rs.getAttrs}) } -func (rs *REST) Watch(ctx api.Context, label, field labels.Selector, resourceVersion string) (watch.Interface, error) { +func (rs *REST) Watch(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) { return rs.registry.WatchPredicate(ctx, &generic.SelectionPredicate{label, field, rs.getAttrs}, resourceVersion) } diff --git a/pkg/registry/namespace/rest_test.go b/pkg/registry/namespace/rest_test.go index 9a694984489..9f15d992fbf 100644 --- a/pkg/registry/namespace/rest_test.go +++ b/pkg/registry/namespace/rest_test.go @@ -22,6 +22,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" @@ -155,7 +156,7 @@ func TestRESTList(t *testing.T) { reg.ObjectList = &api.NamespaceList{ Items: []api.Namespace{*namespaceA, *namespaceB, *namespaceC}, } - got, err := rest.List(api.NewContext(), labels.Everything(), labels.Everything()) + got, err := rest.List(api.NewContext(), labels.Everything(), fields.Everything()) if err != nil { t.Fatalf("Unexpected error %v", err) } @@ -170,7 +171,7 @@ func TestRESTList(t *testing.T) { func TestRESTWatch(t *testing.T) { namespaceA := testNamespace("foo") reg, rest := NewTestREST() - wi, err := rest.Watch(api.NewContext(), labels.Everything(), labels.Everything(), "0") + wi, err := rest.Watch(api.NewContext(), labels.Everything(), fields.Everything(), "0") if err != nil { t.Fatalf("Unexpected error %v", err) } diff --git a/pkg/registry/pod/etcd/etcd.go b/pkg/registry/pod/etcd/etcd.go index d0f1c43857e..c60d9b1c42b 100644 --- a/pkg/registry/pod/etcd/etcd.go +++ b/pkg/registry/pod/etcd/etcd.go @@ -24,6 +24,7 @@ import ( etcderr "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors/etcd" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest" "github.com/GoogleCloudPlatform/kubernetes/pkg/constraint" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic" etcdgeneric "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic/etcd" @@ -55,7 +56,7 @@ func NewREST(h tools.EtcdHelper, factory pod.BoundPodFactory) (*REST, *BindingRE ObjectNameFunc: func(obj runtime.Object) (string, error) { return obj.(*api.Pod).Name, nil }, - PredicateFunc: func(label, field labels.Selector) generic.Matcher { + PredicateFunc: func(label labels.Selector, field fields.Selector) generic.Matcher { return pod.MatchPod(label, field) }, EndpointName: "pods", @@ -96,12 +97,12 @@ func (r *REST) NewList() runtime.Object { } // List obtains a list of pods with labels that match selector. -func (r *REST) List(ctx api.Context, label, field labels.Selector) (runtime.Object, error) { +func (r *REST) List(ctx api.Context, label labels.Selector, field fields.Selector) (runtime.Object, error) { return r.store.List(ctx, label, field) } // Watch begins watching for new, changed, or deleted pods. -func (r *REST) Watch(ctx api.Context, label, field labels.Selector, resourceVersion string) (watch.Interface, error) { +func (r *REST) Watch(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) { return r.store.Watch(ctx, label, field, resourceVersion) } diff --git a/pkg/registry/pod/etcd/etcd_test.go b/pkg/registry/pod/etcd/etcd_test.go index 77f45d6c1c2..c7853e75b42 100644 --- a/pkg/registry/pod/etcd/etcd_test.go +++ b/pkg/registry/pod/etcd/etcd_test.go @@ -29,6 +29,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest/resttest" "github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver" "github.com/GoogleCloudPlatform/kubernetes/pkg/client" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/pod" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" @@ -179,7 +180,7 @@ func TestListError(t *testing.T) { storage, _, _ := NewREST(helper, nil) cache := &fakeCache{} storage = storage.WithPodStatus(cache) - pods, err := storage.List(api.NewDefaultContext(), labels.Everything(), labels.Everything()) + pods, err := storage.List(api.NewDefaultContext(), labels.Everything(), fields.Everything()) if err != fakeEtcdClient.Err { t.Fatalf("Expected %#v, Got %#v", fakeEtcdClient.Err, err) } @@ -208,7 +209,7 @@ func TestListCacheError(t *testing.T) { cache := &fakeCache{errorToReturn: client.ErrPodInfoNotAvailable} storage = storage.WithPodStatus(cache) - pods, err := storage.List(api.NewDefaultContext(), labels.Everything(), labels.Everything()) + pods, err := storage.List(api.NewDefaultContext(), labels.Everything(), fields.Everything()) if err != nil { t.Fatalf("Expected no error, got %#v", err) } @@ -232,7 +233,7 @@ func TestListEmptyPodList(t *testing.T) { storage, _, _ := NewREST(helper, nil) cache := &fakeCache{} storage = storage.WithPodStatus(cache) - pods, err := storage.List(api.NewContext(), labels.Everything(), labels.Everything()) + pods, err := storage.List(api.NewContext(), labels.Everything(), fields.Everything()) if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -271,7 +272,7 @@ func TestListPodList(t *testing.T) { cache := &fakeCache{statusToReturn: &api.PodStatus{Phase: api.PodRunning}} storage = storage.WithPodStatus(cache) - podsObj, err := storage.List(api.NewDefaultContext(), labels.Everything(), labels.Everything()) + podsObj, err := storage.List(api.NewDefaultContext(), labels.Everything(), fields.Everything()) pods := podsObj.(*api.PodList) if err != nil { t.Fatalf("unexpected error: %v", err) @@ -357,7 +358,7 @@ func TestListPodListSelection(t *testing.T) { t.Errorf("unexpected error: %v", err) continue } - field, err := labels.ParseSelector(item.field) + field, err := fields.ParseSelector(item.field) if err != nil { t.Errorf("unexpected error: %v", err) continue @@ -1451,7 +1452,7 @@ func TestEtcdEmptyList(t *testing.T) { E: nil, } - obj, err := registry.List(ctx, labels.Everything(), labels.Everything()) + obj, err := registry.List(ctx, labels.Everything(), fields.Everything()) if err != nil { t.Errorf("unexpected error: %v", err) } @@ -1469,7 +1470,7 @@ func TestEtcdListNotFound(t *testing.T) { R: &etcd.Response{}, E: tools.EtcdErrorNotFound, } - obj, err := registry.List(ctx, labels.Everything(), labels.Everything()) + obj, err := registry.List(ctx, labels.Everything(), fields.Everything()) if err != nil { t.Errorf("unexpected error: %v", err) } @@ -1504,7 +1505,7 @@ func TestEtcdList(t *testing.T) { }, E: nil, } - obj, err := registry.List(ctx, labels.Everything(), labels.Everything()) + obj, err := registry.List(ctx, labels.Everything(), fields.Everything()) if err != nil { t.Errorf("unexpected error: %v", err) } @@ -1524,7 +1525,7 @@ func TestEtcdWatchPods(t *testing.T) { ctx := api.NewDefaultContext() watching, err := registry.Watch(ctx, labels.Everything(), - labels.Everything(), + fields.Everything(), "1", ) if err != nil { @@ -1551,7 +1552,7 @@ func TestEtcdWatchPodsMatch(t *testing.T) { ctx := api.NewDefaultContext() watching, err := registry.Watch(ctx, labels.SelectorFromSet(labels.Set{"name": "foo"}), - labels.Everything(), + fields.Everything(), "1", ) if err != nil { @@ -1590,7 +1591,7 @@ func TestEtcdWatchPodsNotMatch(t *testing.T) { ctx := api.NewDefaultContext() watching, err := registry.Watch(ctx, labels.SelectorFromSet(labels.Set{"name": "foo"}), - labels.Everything(), + fields.Everything(), "1", ) if err != nil { diff --git a/pkg/registry/pod/registry.go b/pkg/registry/pod/registry.go index 23b99e31925..ea45b49ad20 100644 --- a/pkg/registry/pod/registry.go +++ b/pkg/registry/pod/registry.go @@ -19,6 +19,7 @@ package pod import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" "github.com/GoogleCloudPlatform/kubernetes/pkg/watch" @@ -29,7 +30,7 @@ type Registry interface { // ListPods obtains a list of pods having labels which match selector. ListPods(ctx api.Context, selector labels.Selector) (*api.PodList, error) // Watch for new/changed/deleted pods - WatchPods(ctx api.Context, label, field labels.Selector, resourceVersion string) (watch.Interface, error) + WatchPods(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) // Get a specific pod GetPod(ctx api.Context, podID string) (*api.Pod, error) // Create a pod based on a specification. @@ -64,14 +65,14 @@ func NewRegistry(s Storage) Registry { } func (s *storage) ListPods(ctx api.Context, label labels.Selector) (*api.PodList, error) { - obj, err := s.List(ctx, label, labels.Everything()) + obj, err := s.List(ctx, label, fields.Everything()) if err != nil { return nil, err } return obj.(*api.PodList), nil } -func (s *storage) WatchPods(ctx api.Context, label, field labels.Selector, resourceVersion string) (watch.Interface, error) { +func (s *storage) WatchPods(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) { return s.Watch(ctx, label, field, resourceVersion) } diff --git a/pkg/registry/pod/rest.go b/pkg/registry/pod/rest.go index d992e970ead..4b80d371ae0 100644 --- a/pkg/registry/pod/rest.go +++ b/pkg/registry/pod/rest.go @@ -24,6 +24,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" @@ -116,7 +117,7 @@ func PodStatusReset(cache PodStatusGetter) rest.ObjectFunc { } // MatchPod returns a generic matcher for a given label and field selector. -func MatchPod(label, field labels.Selector) generic.Matcher { +func MatchPod(label labels.Selector, field fields.Selector) generic.Matcher { return generic.MatcherFunc(func(obj runtime.Object) (bool, error) { podObj, ok := obj.(*api.Pod) if !ok { diff --git a/pkg/registry/registrytest/controller.go b/pkg/registry/registrytest/controller.go index 40ff0335235..6fe8e5cb32f 100644 --- a/pkg/registry/registrytest/controller.go +++ b/pkg/registry/registrytest/controller.go @@ -20,6 +20,7 @@ import ( "sync" "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/watch" ) @@ -67,7 +68,7 @@ func (r *ControllerRegistry) DeleteController(ctx api.Context, ID string) error return r.Err } -func (r *ControllerRegistry) WatchControllers(ctx api.Context, label, field labels.Selector, resourceVersion string) (watch.Interface, error) { +func (r *ControllerRegistry) WatchControllers(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) { r.Lock() defer r.Unlock() return nil, r.Err diff --git a/pkg/registry/registrytest/endpoint.go b/pkg/registry/registrytest/endpoint.go index d4d814a30d0..1d94ee2b58f 100644 --- a/pkg/registry/registrytest/endpoint.go +++ b/pkg/registry/registrytest/endpoint.go @@ -22,6 +22,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/watch" ) @@ -60,7 +61,7 @@ func (e *EndpointRegistry) GetEndpoints(ctx api.Context, name string) (*api.Endp return nil, errors.NewNotFound("Endpoints", name) } -func (e *EndpointRegistry) WatchEndpoints(ctx api.Context, labels, fields labels.Selector, resourceVersion string) (watch.Interface, error) { +func (e *EndpointRegistry) WatchEndpoints(ctx api.Context, labels labels.Selector, fields fields.Selector, resourceVersion string) (watch.Interface, error) { return nil, fmt.Errorf("unimplemented!") } diff --git a/pkg/registry/registrytest/minion.go b/pkg/registry/registrytest/minion.go index c44b2802e2e..5eef464d4a0 100644 --- a/pkg/registry/registrytest/minion.go +++ b/pkg/registry/registrytest/minion.go @@ -21,6 +21,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/watch" ) @@ -111,6 +112,6 @@ func (r *MinionRegistry) DeleteMinion(ctx api.Context, minionID string) error { return r.Err } -func (r *MinionRegistry) WatchMinions(ctx api.Context, label, field labels.Selector, resourceVersion string) (watch.Interface, error) { +func (r *MinionRegistry) WatchMinions(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) { return nil, r.Err } diff --git a/pkg/registry/registrytest/pod.go b/pkg/registry/registrytest/pod.go index 6bfa0eed471..3d19baf2887 100644 --- a/pkg/registry/registrytest/pod.go +++ b/pkg/registry/registrytest/pod.go @@ -20,6 +20,7 @@ import ( "sync" "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/watch" ) @@ -69,7 +70,7 @@ func (r *PodRegistry) ListPods(ctx api.Context, selector labels.Selector) (*api. }) } -func (r *PodRegistry) WatchPods(ctx api.Context, label, field labels.Selector, resourceVersion string) (watch.Interface, error) { +func (r *PodRegistry) WatchPods(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) { return r.broadcaster.Watch(), nil } diff --git a/pkg/registry/registrytest/service.go b/pkg/registry/registrytest/service.go index 28349b3f5bd..ecf4af03d05 100644 --- a/pkg/registry/registrytest/service.go +++ b/pkg/registry/registrytest/service.go @@ -20,6 +20,7 @@ import ( "sync" "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/watch" ) @@ -107,7 +108,7 @@ func (r *ServiceRegistry) UpdateService(ctx api.Context, svc *api.Service) (*api return svc, r.Err } -func (r *ServiceRegistry) WatchServices(ctx api.Context, label labels.Selector, field labels.Selector, resourceVersion string) (watch.Interface, error) { +func (r *ServiceRegistry) WatchServices(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) { r.mu.Lock() defer r.mu.Unlock() @@ -137,7 +138,7 @@ func (r *ServiceRegistry) UpdateEndpoints(ctx api.Context, e *api.Endpoints) err return r.Err } -func (r *ServiceRegistry) WatchEndpoints(ctx api.Context, label, field labels.Selector, resourceVersion string) (watch.Interface, error) { +func (r *ServiceRegistry) WatchEndpoints(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) { r.mu.Lock() defer r.mu.Unlock() diff --git a/pkg/registry/resourcequota/rest.go b/pkg/registry/resourcequota/rest.go index 98616f2a351..0938b8b1a27 100644 --- a/pkg/registry/resourcequota/rest.go +++ b/pkg/registry/resourcequota/rest.go @@ -22,6 +22,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" @@ -133,15 +134,15 @@ func (rs *REST) Get(ctx api.Context, name string) (runtime.Object, error) { return resourceQuota, err } -func (rs *REST) getAttrs(obj runtime.Object) (objLabels, objFields labels.Set, err error) { - return labels.Set{}, labels.Set{}, nil +func (rs *REST) getAttrs(obj runtime.Object) (objLabels labels.Set, objFields fields.Set, err error) { + return labels.Set{}, fields.Set{}, nil } -func (rs *REST) List(ctx api.Context, label, field labels.Selector) (runtime.Object, error) { +func (rs *REST) List(ctx api.Context, label labels.Selector, field fields.Selector) (runtime.Object, error) { return rs.registry.ListPredicate(ctx, &generic.SelectionPredicate{label, field, rs.getAttrs}) } -func (rs *REST) Watch(ctx api.Context, label, field labels.Selector, resourceVersion string) (watch.Interface, error) { +func (rs *REST) Watch(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) { return rs.registry.WatchPredicate(ctx, &generic.SelectionPredicate{label, field, rs.getAttrs}, resourceVersion) } diff --git a/pkg/registry/resourcequota/rest_test.go b/pkg/registry/resourcequota/rest_test.go index fb18fd6f346..3b039b723c0 100644 --- a/pkg/registry/resourcequota/rest_test.go +++ b/pkg/registry/resourcequota/rest_test.go @@ -24,6 +24,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" @@ -77,7 +78,7 @@ func TestList(t *testing.T) { }) ctx := api.NewDefaultContext() - obj, err := rest.List(ctx, labels.Set{}.AsSelector(), labels.Set{}.AsSelector()) + obj, err := rest.List(ctx, labels.Set{}.AsSelector(), fields.Set{}.AsSelector()) if err != nil { t.Errorf("unexpected error: %v", err) } @@ -89,7 +90,7 @@ func TestList(t *testing.T) { t.Errorf("unexpected list object: %v", obj) } - obj, err = rest.List(ctx, labels.Set{"foo": "bar"}.AsSelector(), labels.Set{}.AsSelector()) + obj, err = rest.List(ctx, labels.Set{"foo": "bar"}.AsSelector(), fields.Set{}.AsSelector()) if err != nil { t.Errorf("unexpected error: %v", err) } diff --git a/pkg/registry/secret/rest.go b/pkg/registry/secret/rest.go index 265d23c5544..a9b7daca5f3 100644 --- a/pkg/registry/secret/rest.go +++ b/pkg/registry/secret/rest.go @@ -22,6 +22,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" @@ -133,22 +134,22 @@ func (rs *REST) Get(ctx api.Context, name string) (runtime.Object, error) { return secret, err } -func (rs *REST) getAttrs(obj runtime.Object) (objLabels, objFields labels.Set, err error) { +func (rs *REST) getAttrs(obj runtime.Object) (objLabels labels.Set, objFields fields.Set, err error) { secret, ok := obj.(*api.Secret) if !ok { return nil, nil, fmt.Errorf("invalid object type") } - return labels.Set{}, labels.Set{ + return labels.Set{}, fields.Set{ "type": string(secret.Type), }, nil } -func (rs *REST) List(ctx api.Context, label, field labels.Selector) (runtime.Object, error) { +func (rs *REST) List(ctx api.Context, label labels.Selector, field fields.Selector) (runtime.Object, error) { return rs.registry.ListPredicate(ctx, &generic.SelectionPredicate{label, field, rs.getAttrs}) } -func (rs *REST) Watch(ctx api.Context, label, field labels.Selector, resourceVersion string) (watch.Interface, error) { +func (rs *REST) Watch(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) { return rs.registry.WatchPredicate(ctx, &generic.SelectionPredicate{label, field, rs.getAttrs}, resourceVersion) } diff --git a/pkg/registry/secret/rest_test.go b/pkg/registry/secret/rest_test.go index f905378c2d1..d035304fb90 100644 --- a/pkg/registry/secret/rest_test.go +++ b/pkg/registry/secret/rest_test.go @@ -22,6 +22,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" @@ -163,7 +164,7 @@ func TestRESTgetAttrs(t *testing.T) { if e, a := label, (labels.Set{}); !reflect.DeepEqual(e, a) { t.Errorf("diff: %s", util.ObjectDiff(e, a)) } - expect := labels.Set{ + expect := fields.Set{ "type": string(api.SecretTypeOpaque), } if e, a := expect, field; !reflect.DeepEqual(e, a) { @@ -183,7 +184,7 @@ func TestRESTList(t *testing.T) { reg.ObjectList = &api.SecretList{ Items: []api.Secret{*secretA, *secretB, *secretC}, } - got, err := rest.List(api.NewContext(), labels.Everything(), labels.Everything()) + got, err := rest.List(api.NewContext(), labels.Everything(), fields.Everything()) if err != nil { t.Fatalf("Unexpected error %v", err) } @@ -198,7 +199,7 @@ func TestRESTList(t *testing.T) { func TestRESTWatch(t *testing.T) { secretA := testSecret("a") reg, rest := NewTestREST() - wi, err := rest.Watch(api.NewContext(), labels.Everything(), labels.Everything(), "0") + wi, err := rest.Watch(api.NewContext(), labels.Everything(), fields.Everything(), "0") if err != nil { t.Fatalf("Unexpected error %v", err) } diff --git a/pkg/registry/service/registry.go b/pkg/registry/service/registry.go index 478e6633415..2cca93568d8 100644 --- a/pkg/registry/service/registry.go +++ b/pkg/registry/service/registry.go @@ -18,6 +18,7 @@ package service import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/endpoint" "github.com/GoogleCloudPlatform/kubernetes/pkg/watch" @@ -30,7 +31,7 @@ type Registry interface { GetService(ctx api.Context, name string) (*api.Service, error) DeleteService(ctx api.Context, name string) error UpdateService(ctx api.Context, svc *api.Service) (*api.Service, error) - WatchServices(ctx api.Context, labels, fields labels.Selector, resourceVersion string) (watch.Interface, error) + WatchServices(ctx api.Context, labels labels.Selector, fields fields.Selector, resourceVersion string) (watch.Interface, error) // TODO: endpoints and their implementation should be separated, setting endpoints should be // supported via the API, and the endpoints-controller should use the API to update endpoints. diff --git a/pkg/registry/service/rest.go b/pkg/registry/service/rest.go index aa761e50b7c..3875b0019e0 100644 --- a/pkg/registry/service/rest.go +++ b/pkg/registry/service/rest.go @@ -27,6 +27,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation" "github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/minion" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" @@ -151,8 +152,7 @@ func (rs *REST) Get(ctx api.Context, id string) (runtime.Object, error) { return service, err } -// TODO: implement field selector? -func (rs *REST) List(ctx api.Context, label, field labels.Selector) (runtime.Object, error) { +func (rs *REST) List(ctx api.Context, label labels.Selector, field fields.Selector) (runtime.Object, error) { list, err := rs.registry.ListServices(ctx) if err != nil { return nil, err @@ -169,7 +169,7 @@ func (rs *REST) List(ctx api.Context, label, field labels.Selector) (runtime.Obj // Watch returns Services events via a watch.Interface. // It implements apiserver.ResourceWatcher. -func (rs *REST) Watch(ctx api.Context, label, field labels.Selector, resourceVersion string) (watch.Interface, error) { +func (rs *REST) Watch(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) { return rs.registry.WatchServices(ctx, label, field, resourceVersion) } diff --git a/pkg/registry/service/rest_test.go b/pkg/registry/service/rest_test.go index 56b734a3e0e..9da69125464 100644 --- a/pkg/registry/service/rest_test.go +++ b/pkg/registry/service/rest_test.go @@ -27,6 +27,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest/resttest" "github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver" cloud "github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider/fake" + "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest" ) @@ -421,7 +422,7 @@ func TestServiceRegistryList(t *testing.T) { }, }) registry.List.ResourceVersion = "1" - s, _ := storage.List(ctx, labels.Everything(), labels.Everything()) + s, _ := storage.List(ctx, labels.Everything(), fields.Everything()) sl := s.(*api.ServiceList) if len(fakeCloud.Calls) != 0 { t.Errorf("Unexpected call(s): %#v", fakeCloud.Calls)