diff --git a/examples/apiserver/rest/reststorage.go b/examples/apiserver/rest/reststorage.go index 52de661bf03..68a54582eee 100644 --- a/examples/apiserver/rest/reststorage.go +++ b/examples/apiserver/rest/reststorage.go @@ -17,6 +17,8 @@ limitations under the License. package rest import ( + "fmt" + "k8s.io/kubernetes/cmd/libs/go2idl/client-gen/test_apis/testgroup.k8s.io" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/fields" @@ -59,8 +61,18 @@ func NewREST(config *storagebackend.Config, storageDecorator generic.StorageDeco return obj.(*testgroup.TestType).Name, nil }, // Used to match objects based on labels/fields for list. - PredicateFunc: func(label labels.Selector, field fields.Selector) generic.Matcher { - return generic.MatcherFunc(nil) + PredicateFunc: func(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { + return &generic.SelectionPredicate{ + Label: label, + Field: field, + GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) { + testType, ok := obj.(*testgroup.TestType) + if !ok { + return nil, nil, fmt.Errorf("unexpected type of given object") + } + return labels.Set(testType.ObjectMeta.Labels), fields.Set{}, nil + }, + } }, Storage: storageInterface, } diff --git a/federation/registry/cluster/strategy.go b/federation/registry/cluster/strategy.go index fe04259341f..9b12d487a44 100644 --- a/federation/registry/cluster/strategy.go +++ b/federation/registry/cluster/strategy.go @@ -44,7 +44,7 @@ func ClusterToSelectableFields(cluster *federation.Cluster) fields.Set { return generic.ObjectMetaFieldsSet(cluster.ObjectMeta, false) } -func MatchCluster(label labels.Selector, field fields.Selector) generic.Matcher { +func MatchCluster(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { return &generic.SelectionPredicate{ Label: label, Field: field, diff --git a/federation/registry/cluster/strategy_test.go b/federation/registry/cluster/strategy_test.go index c1ec426d5ba..e7f4487ffd3 100644 --- a/federation/registry/cluster/strategy_test.go +++ b/federation/registry/cluster/strategy_test.go @@ -157,7 +157,7 @@ func TestSelectableFieldLabelConversions(t *testing.T) { apitesting.TestSelectableFieldLabelConversionsOfKind(t, testapi.Federation.GroupVersion().String(), "Cluster", - labels.Set(ClusterToSelectableFields(&federation.Cluster{})), + ClusterToSelectableFields(&federation.Cluster{}), nil, ) } diff --git a/pkg/api/testing/conversion.go b/pkg/api/testing/conversion.go index 136d25a37fe..e3360958bda 100644 --- a/pkg/api/testing/conversion.go +++ b/pkg/api/testing/conversion.go @@ -20,14 +20,14 @@ import ( "testing" "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/labels" + "k8s.io/kubernetes/pkg/fields" ) // TestSelectableFieldLabelConversions verifies that given resource have field // label conversion defined for each its selectable field. // fields contains selectable fields of the resource. // labelMap maps deprecated labels to their canonical names. -func TestSelectableFieldLabelConversionsOfKind(t *testing.T, apiVersion string, kind string, fields labels.Set, labelMap map[string]string) { +func TestSelectableFieldLabelConversionsOfKind(t *testing.T, apiVersion string, kind string, fields fields.Set, labelMap map[string]string) { badFieldLabels := []string{ "name", ".name", diff --git a/pkg/registry/certificates/etcd/etcd.go b/pkg/registry/certificates/etcd/etcd.go index 4ac75cf723c..041430b877b 100644 --- a/pkg/registry/certificates/etcd/etcd.go +++ b/pkg/registry/certificates/etcd/etcd.go @@ -62,7 +62,7 @@ func NewREST(opts generic.RESTOptions) (*REST, *StatusREST, *ApprovalREST) { ObjectNameFunc: func(obj runtime.Object) (string, error) { return obj.(*certificates.CertificateSigningRequest).Name, nil }, - PredicateFunc: func(label labels.Selector, field fields.Selector) generic.Matcher { + PredicateFunc: func(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { return csrregistry.Matcher(label, field) }, QualifiedResource: certificates.Resource("certificatesigningrequests"), diff --git a/pkg/registry/certificates/strategy.go b/pkg/registry/certificates/strategy.go index 03e4659aa2d..3928a4131b0 100644 --- a/pkg/registry/certificates/strategy.go +++ b/pkg/registry/certificates/strategy.go @@ -168,18 +168,21 @@ func (csrApprovalStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Obje } // Matcher returns a generic matcher for a given label and field selector. -func Matcher(label labels.Selector, field fields.Selector) generic.Matcher { - return generic.MatcherFunc(func(obj runtime.Object) (bool, error) { - sa, ok := obj.(*certificates.CertificateSigningRequest) - if !ok { - return false, fmt.Errorf("not a CertificateSigningRequest") - } - fields := SelectableFields(sa) - return label.Matches(labels.Set(sa.Labels)) && field.Matches(fields), nil - }) +func Matcher(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { + return &generic.SelectionPredicate{ + Label: label, + Field: field, + GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) { + sa, ok := obj.(*certificates.CertificateSigningRequest) + if !ok { + return nil, nil, fmt.Errorf("not a CertificateSigningRequest") + } + return labels.Set(sa.Labels), SelectableFields(sa), nil + }, + } } -// SelectableFields returns a label set that can be used for filter selection -func SelectableFields(obj *certificates.CertificateSigningRequest) labels.Set { - return labels.Set{} +// SelectableFields returns a field set that can be used for filter selection +func SelectableFields(obj *certificates.CertificateSigningRequest) fields.Set { + return nil } diff --git a/pkg/registry/clusterrole/strategy.go b/pkg/registry/clusterrole/strategy.go index f148a8ca2c5..68950ea4555 100644 --- a/pkg/registry/clusterrole/strategy.go +++ b/pkg/registry/clusterrole/strategy.go @@ -102,18 +102,21 @@ func (s strategy) Export(ctx api.Context, obj runtime.Object, exact bool) error } // Matcher returns a generic matcher for a given label and field selector. -func Matcher(label labels.Selector, field fields.Selector) generic.Matcher { - return generic.MatcherFunc(func(obj runtime.Object) (bool, error) { - sa, ok := obj.(*rbac.ClusterRole) - if !ok { - return false, fmt.Errorf("not a ClusterRole") - } - fields := SelectableFields(sa) - return label.Matches(labels.Set(sa.Labels)) && field.Matches(fields), nil - }) +func Matcher(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { + return &generic.SelectionPredicate{ + Label: label, + Field: field, + GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) { + role, ok := obj.(*rbac.ClusterRole) + if !ok { + return nil, nil, fmt.Errorf("not a ClusterRole") + } + return labels.Set(role.Labels), SelectableFields(role), nil + }, + } } -// SelectableFields returns a label set that can be used for filter selection -func SelectableFields(obj *rbac.ClusterRole) labels.Set { - return labels.Set{} +// SelectableFields returns a field set that can be used for filter selection +func SelectableFields(obj *rbac.ClusterRole) fields.Set { + return nil } diff --git a/pkg/registry/clusterrolebinding/strategy.go b/pkg/registry/clusterrolebinding/strategy.go index 78fb2d052a0..102a8533ef7 100644 --- a/pkg/registry/clusterrolebinding/strategy.go +++ b/pkg/registry/clusterrolebinding/strategy.go @@ -102,18 +102,21 @@ func (s strategy) Export(ctx api.Context, obj runtime.Object, exact bool) error } // Matcher returns a generic matcher for a given label and field selector. -func Matcher(label labels.Selector, field fields.Selector) generic.Matcher { - return generic.MatcherFunc(func(obj runtime.Object) (bool, error) { - sa, ok := obj.(*rbac.ClusterRoleBinding) - if !ok { - return false, fmt.Errorf("not a ClusterRoleBinding") - } - fields := SelectableFields(sa) - return label.Matches(labels.Set(sa.Labels)) && field.Matches(fields), nil - }) +func Matcher(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { + return &generic.SelectionPredicate{ + Label: label, + Field: field, + GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) { + roleBinding, ok := obj.(*rbac.ClusterRoleBinding) + if !ok { + return nil, nil, fmt.Errorf("not a ClusterRoleBinding") + } + return labels.Set(roleBinding.Labels), SelectableFields(roleBinding), nil + }, + } } -// SelectableFields returns a label set that can be used for filter selection -func SelectableFields(obj *rbac.ClusterRoleBinding) labels.Set { - return labels.Set{} +// SelectableFields returns a field set that can be used for filter selection +func SelectableFields(obj *rbac.ClusterRoleBinding) fields.Set { + return nil } diff --git a/pkg/registry/configmap/strategy.go b/pkg/registry/configmap/strategy.go index d4227bc18e3..bbac7e86b1f 100644 --- a/pkg/registry/configmap/strategy.go +++ b/pkg/registry/configmap/strategy.go @@ -88,7 +88,7 @@ func ConfigMapToSelectableFields(cfg *api.ConfigMap) fields.Set { } // MatchConfigMap returns a generic matcher for a given label and field selector. -func MatchConfigMap(label labels.Selector, field fields.Selector) generic.Matcher { +func MatchConfigMap(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { return &generic.SelectionPredicate{ Label: label, Field: field, diff --git a/pkg/registry/configmap/strategy_test.go b/pkg/registry/configmap/strategy_test.go index 0b6d79ab89e..aee36056756 100644 --- a/pkg/registry/configmap/strategy_test.go +++ b/pkg/registry/configmap/strategy_test.go @@ -22,7 +22,6 @@ import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/testapi" apitesting "k8s.io/kubernetes/pkg/api/testing" - "k8s.io/kubernetes/pkg/labels" ) func TestConfigMapStrategy(t *testing.T) { @@ -74,7 +73,7 @@ func TestSelectableFieldLabelConversions(t *testing.T) { apitesting.TestSelectableFieldLabelConversionsOfKind(t, testapi.Default.GroupVersion().String(), "ConfigMap", - labels.Set(ConfigMapToSelectableFields(&api.ConfigMap{})), + ConfigMapToSelectableFields(&api.ConfigMap{}), nil, ) } diff --git a/pkg/registry/controller/strategy.go b/pkg/registry/controller/strategy.go index 62e5ecad094..6b96706b604 100644 --- a/pkg/registry/controller/strategy.go +++ b/pkg/registry/controller/strategy.go @@ -113,7 +113,7 @@ func ControllerToSelectableFields(controller *api.ReplicationController) fields. // MatchController is the filter used by the generic etcd backend to route // watch events from etcd to clients of the apiserver only interested in specific // labels/fields. -func MatchController(label labels.Selector, field fields.Selector) generic.Matcher { +func MatchController(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { return &generic.SelectionPredicate{ Label: label, Field: field, diff --git a/pkg/registry/controller/strategy_test.go b/pkg/registry/controller/strategy_test.go index ac09ca2e40d..192221c9395 100644 --- a/pkg/registry/controller/strategy_test.go +++ b/pkg/registry/controller/strategy_test.go @@ -22,7 +22,6 @@ import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/testapi" apitesting "k8s.io/kubernetes/pkg/api/testing" - "k8s.io/kubernetes/pkg/labels" ) func TestControllerStrategy(t *testing.T) { @@ -146,7 +145,7 @@ func TestSelectableFieldLabelConversions(t *testing.T) { apitesting.TestSelectableFieldLabelConversionsOfKind(t, testapi.Default.GroupVersion().String(), "ReplicationController", - labels.Set(ControllerToSelectableFields(&api.ReplicationController{})), + ControllerToSelectableFields(&api.ReplicationController{}), nil, ) } diff --git a/pkg/registry/daemonset/strategy.go b/pkg/registry/daemonset/strategy.go index 3d7987f30f4..de5690545a3 100644 --- a/pkg/registry/daemonset/strategy.go +++ b/pkg/registry/daemonset/strategy.go @@ -112,7 +112,7 @@ func DaemonSetToSelectableFields(daemon *extensions.DaemonSet) fields.Set { // MatchSetDaemon is the filter used by the generic etcd backend to route // watch events from etcd to clients of the apiserver only interested in specific // labels/fields. -func MatchDaemonSet(label labels.Selector, field fields.Selector) generic.Matcher { +func MatchDaemonSet(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { return &generic.SelectionPredicate{ Label: label, Field: field, diff --git a/pkg/registry/daemonset/strategy_test.go b/pkg/registry/daemonset/strategy_test.go index 00f8a2b1688..306eccd307a 100644 --- a/pkg/registry/daemonset/strategy_test.go +++ b/pkg/registry/daemonset/strategy_test.go @@ -23,14 +23,13 @@ import ( "k8s.io/kubernetes/pkg/api/testapi" apitesting "k8s.io/kubernetes/pkg/api/testing" "k8s.io/kubernetes/pkg/apis/extensions" - "k8s.io/kubernetes/pkg/labels" ) func TestSelectableFieldLabelConversions(t *testing.T) { apitesting.TestSelectableFieldLabelConversionsOfKind(t, testapi.Extensions.GroupVersion().String(), "DaemonSet", - labels.Set(DaemonSetToSelectableFields(&extensions.DaemonSet{})), + DaemonSetToSelectableFields(&extensions.DaemonSet{}), nil, ) } diff --git a/pkg/registry/deployment/strategy.go b/pkg/registry/deployment/strategy.go index 540d8b74c8c..e460685b373 100644 --- a/pkg/registry/deployment/strategy.go +++ b/pkg/registry/deployment/strategy.go @@ -118,7 +118,7 @@ func DeploymentToSelectableFields(deployment *extensions.Deployment) fields.Set // MatchDeployment is the filter used by the generic etcd backend to route // watch events from etcd to clients of the apiserver only interested in specific // labels/fields. -func MatchDeployment(label labels.Selector, field fields.Selector) generic.Matcher { +func MatchDeployment(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { return &generic.SelectionPredicate{ Label: label, Field: field, diff --git a/pkg/registry/deployment/strategy_test.go b/pkg/registry/deployment/strategy_test.go index e7575276b63..6e07902e56a 100644 --- a/pkg/registry/deployment/strategy_test.go +++ b/pkg/registry/deployment/strategy_test.go @@ -24,7 +24,6 @@ import ( "k8s.io/kubernetes/pkg/api/testapi" apitesting "k8s.io/kubernetes/pkg/api/testing" "k8s.io/kubernetes/pkg/apis/extensions" - "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/runtime" ) @@ -32,7 +31,7 @@ func TestSelectableFieldLabelConversions(t *testing.T) { apitesting.TestSelectableFieldLabelConversionsOfKind(t, testapi.Extensions.GroupVersion().String(), "Deployment", - labels.Set(DeploymentToSelectableFields(&extensions.Deployment{})), + DeploymentToSelectableFields(&extensions.Deployment{}), nil, ) } diff --git a/pkg/registry/endpoint/strategy.go b/pkg/registry/endpoint/strategy.go index f307f8b32c7..903c9e13de7 100644 --- a/pkg/registry/endpoint/strategy.go +++ b/pkg/registry/endpoint/strategy.go @@ -79,7 +79,7 @@ func (endpointsStrategy) AllowUnconditionalUpdate() bool { } // MatchEndpoints returns a generic matcher for a given label and field selector. -func MatchEndpoints(label labels.Selector, field fields.Selector) generic.Matcher { +func MatchEndpoints(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { return &generic.SelectionPredicate{Label: label, Field: field, GetAttrs: EndpointsAttributes} } diff --git a/pkg/registry/endpoint/strategy_test.go b/pkg/registry/endpoint/strategy_test.go index 0a4cd87b8be..58d3a249ed0 100644 --- a/pkg/registry/endpoint/strategy_test.go +++ b/pkg/registry/endpoint/strategy_test.go @@ -22,7 +22,6 @@ import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/testapi" apitesting "k8s.io/kubernetes/pkg/api/testing" - "k8s.io/kubernetes/pkg/labels" ) func TestSelectableFieldLabelConversions(t *testing.T) { @@ -33,7 +32,7 @@ func TestSelectableFieldLabelConversions(t *testing.T) { apitesting.TestSelectableFieldLabelConversionsOfKind(t, testapi.Default.GroupVersion().String(), "Endpoints", - labels.Set(fieldsSet), + fieldsSet, nil, ) } diff --git a/pkg/registry/event/strategy.go b/pkg/registry/event/strategy.go index c565eee1b72..bcf363be12f 100644 --- a/pkg/registry/event/strategy.go +++ b/pkg/registry/event/strategy.go @@ -70,7 +70,7 @@ func (eventStrategy) AllowUnconditionalUpdate() bool { return true } -func MatchEvent(label labels.Selector, field fields.Selector) generic.Matcher { +func MatchEvent(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { return &generic.SelectionPredicate{Label: label, Field: field, GetAttrs: getAttrs} } diff --git a/pkg/registry/event/strategy_test.go b/pkg/registry/event/strategy_test.go index ca95a7a90f3..45b6c08fa87 100644 --- a/pkg/registry/event/strategy_test.go +++ b/pkg/registry/event/strategy_test.go @@ -94,7 +94,7 @@ func TestSelectableFieldLabelConversions(t *testing.T) { apitesting.TestSelectableFieldLabelConversionsOfKind(t, testapi.Default.GroupVersion().String(), "Event", - labels.Set(fset), + fset, nil, ) } diff --git a/pkg/registry/generic/matcher.go b/pkg/registry/generic/matcher.go index 3c1b7ecaaeb..61431fe1b6e 100644 --- a/pkg/registry/generic/matcher.go +++ b/pkg/registry/generic/matcher.go @@ -68,7 +68,11 @@ func (s *SelectionPredicate) Matches(obj runtime.Object) (bool, error) { if err != nil { return false, err } - return s.Label.Matches(labels) && s.Field.Matches(fields), nil + matched := s.Label.Matches(labels) + if s.Field != nil { + matched = (matched && s.Field.Matches(fields)) + } + return matched, nil } // MatchesSingle will return (name, true) if and only if s.Field matches on the object's @@ -115,50 +119,7 @@ type Matcher interface { MatcherIndex() []storage.MatchValue } -// MatcherFunc makes a matcher from the provided function. For easy definition -// of matchers for testing. Note: use SelectionPredicate above for real code! -func MatcherFunc(f func(obj runtime.Object) (bool, error)) Matcher { - return matcherFunc(f) -} - -type matcherFunc func(obj runtime.Object) (bool, error) - -// Matches calls the embedded function. -func (m matcherFunc) Matches(obj runtime.Object) (bool, error) { - return m(obj) -} - -// MatchesSingle always returns "", false-- because this is a predicate -// implementation of Matcher. -func (m matcherFunc) MatchesSingle() (string, bool) { - return "", false -} - -// MatcherIndex always returns empty list. -func (m matcherFunc) MatcherIndex() []storage.MatchValue { - return nil -} - -// MatchOnKey returns a matcher that will send only the object matching key -// through the matching function f. For testing! -// Note: use SelectionPredicate above for real code! -func MatchOnKey(key string, f func(obj runtime.Object) (bool, error)) Matcher { - return matchKey{key, f} -} - -type matchKey struct { - key string - matcherFunc -} - -// MatchesSingle always returns its key, true. -func (m matchKey) MatchesSingle() (string, bool) { - return m.key, true -} - var ( // Assert implementations match the interface. - _ = Matcher(matchKey{}) _ = Matcher(&SelectionPredicate{}) - _ = Matcher(matcherFunc(nil)) ) diff --git a/pkg/registry/generic/matcher_test.go b/pkg/registry/generic/matcher_test.go index 80f57a161f4..ebcab4ee2f3 100644 --- a/pkg/registry/generic/matcher_test.go +++ b/pkg/registry/generic/matcher_test.go @@ -117,14 +117,3 @@ func TestSelectionPredicate(t *testing.T) { } } } - -func TestSingleMatch(t *testing.T) { - m := MatchOnKey("pod-name-here", func(obj runtime.Object) (bool, error) { return true, nil }) - got, ok := m.MatchesSingle() - if !ok { - t.Errorf("Expected MatchesSingle to return true") - } - if e, a := "pod-name-here", got; e != a { - t.Errorf("Expected %#v, got %#v", e, a) - } -} diff --git a/pkg/registry/generic/registry/store.go b/pkg/registry/generic/registry/store.go index 949ffd82e66..99ee27691bc 100644 --- a/pkg/registry/generic/registry/store.go +++ b/pkg/registry/generic/registry/store.go @@ -88,7 +88,7 @@ type Store struct { TTLFunc func(obj runtime.Object, existing uint64, update bool) (uint64, error) // Returns a matcher corresponding to the provided labels and fields. - PredicateFunc func(label labels.Selector, field fields.Selector) generic.Matcher + PredicateFunc func(label labels.Selector, field fields.Selector) *generic.SelectionPredicate // DeleteCollectionWorkers is the maximum number of workers in a single // DeleteCollection call. @@ -188,7 +188,7 @@ func (e *Store) List(ctx api.Context, options *api.ListOptions) (runtime.Object, } // ListPredicate returns a list of all the items matching m. -func (e *Store) ListPredicate(ctx api.Context, m generic.Matcher, options *api.ListOptions) (runtime.Object, error) { +func (e *Store) ListPredicate(ctx api.Context, m *generic.SelectionPredicate, options *api.ListOptions) (runtime.Object, error) { list := e.NewListFunc() filter := e.createFilter(m) if name, ok := m.MatchesSingle(); ok { @@ -797,7 +797,7 @@ func (e *Store) Watch(ctx api.Context, options *api.ListOptions) (watch.Interfac } // WatchPredicate starts a watch for the items that m matches. -func (e *Store) WatchPredicate(ctx api.Context, m generic.Matcher, resourceVersion string) (watch.Interface, error) { +func (e *Store) WatchPredicate(ctx api.Context, m *generic.SelectionPredicate, resourceVersion string) (watch.Interface, error) { filter := e.createFilter(m) if name, ok := m.MatchesSingle(); ok { @@ -813,7 +813,7 @@ func (e *Store) WatchPredicate(ctx api.Context, m generic.Matcher, resourceVersi return e.Storage.WatchList(ctx, e.KeyRootFunc(ctx), resourceVersion, filter) } -func (e *Store) createFilter(m generic.Matcher) storage.Filter { +func (e *Store) createFilter(m *generic.SelectionPredicate) storage.Filter { filterFunc := func(obj runtime.Object) bool { matches, err := m.Matches(obj) if err != nil { diff --git a/pkg/registry/generic/registry/store_test.go b/pkg/registry/generic/registry/store_test.go index 373cf2e4cfb..c3eb7a217a8 100644 --- a/pkg/registry/generic/registry/store_test.go +++ b/pkg/registry/generic/registry/store_test.go @@ -83,45 +83,33 @@ func NewTestGenericStoreRegistry(t *testing.T) (*etcdtesting.EtcdTestServer, *St return newTestGenericStoreRegistry(t, false) } -// setMatcher is a matcher that matches any pod with id in the set. +// matchPodName returns selection predicate that matches any pod with name in the set. // Makes testing simpler. -type setMatcher struct { - sets.String -} - -func (sm setMatcher) Matches(obj runtime.Object) (bool, error) { - pod, ok := obj.(*api.Pod) - if !ok { - return false, fmt.Errorf("wrong object") +func matchPodName(names ...string) *generic.SelectionPredicate { + // Note: even if pod name is a field, we have to use labels, + // because field selector doesn't support "IN" operator. + l, err := labels.NewRequirement("name", labels.InOperator, sets.NewString(names...)) + if err != nil { + panic("Labels requirement must validate successfully") } - return sm.Has(pod.Name), nil -} - -func (sm setMatcher) MatchesSingle() (string, bool) { - if sm.Len() == 1 { - // Since pod name is its key, we can optimize this case. - return sm.List()[0], true + return &generic.SelectionPredicate{ + Label: labels.Everything().Add(*l), + Field: fields.Everything(), + GetAttrs: func(obj runtime.Object) (label labels.Set, field fields.Set, err error) { + pod := obj.(*api.Pod) + return labels.Set{"name": pod.ObjectMeta.Name}, nil, nil + }, } - return "", false } -func (sm setMatcher) MatcherIndex() []storage.MatchValue { - return nil -} - -// everythingMatcher matches everything -type everythingMatcher struct{} - -func (everythingMatcher) Matches(obj runtime.Object) (bool, error) { - return true, nil -} - -func (everythingMatcher) MatchesSingle() (string, bool) { - return "", false -} - -func (everythingMatcher) MatcherIndex() []storage.MatchValue { - return nil +func matchEverything() *generic.SelectionPredicate { + return &generic.SelectionPredicate{ + Label: labels.Everything(), + Field: fields.Everything(), + GetAttrs: func(obj runtime.Object) (label labels.Set, field fields.Set, err error) { + return nil, nil, nil + }, + } } func TestStoreList(t *testing.T) { @@ -139,34 +127,34 @@ func TestStoreList(t *testing.T) { table := map[string]struct { in *api.PodList - m generic.Matcher + m *generic.SelectionPredicate out runtime.Object context api.Context }{ "notFound": { in: nil, - m: everythingMatcher{}, + m: matchEverything(), out: &api.PodList{Items: []api.Pod{}}, }, "normal": { in: &api.PodList{Items: []api.Pod{*podA, *podB}}, - m: everythingMatcher{}, + m: matchEverything(), out: &api.PodList{Items: []api.Pod{*podA, *podB}}, }, "normalFiltered": { in: &api.PodList{Items: []api.Pod{*podA, *podB}}, - m: setMatcher{sets.NewString("foo")}, + m: matchPodName("foo"), out: &api.PodList{Items: []api.Pod{*podB}}, }, "normalFilteredNoNamespace": { in: &api.PodList{Items: []api.Pod{*podA, *podB}}, - m: setMatcher{sets.NewString("foo")}, + m: matchPodName("foo"), out: &api.PodList{Items: []api.Pod{*podB}}, context: noNamespaceContext, }, "normalFilteredMatchMultiple": { in: &api.PodList{Items: []api.Pod{*podA, *podB}}, - m: setMatcher{sets.NewString("foo", "makeMatchSingleReturnFalse")}, + m: matchPodName("foo", "makeMatchSingleReturnFalse"), out: &api.PodList{Items: []api.Pod{*podB}}, }, } @@ -930,7 +918,7 @@ func TestStoreDeleteCollectionWithWatch(t *testing.T) { } podCreated := objCreated.(*api.Pod) - watcher, err := registry.WatchPredicate(testContext, setMatcher{sets.NewString("foo")}, podCreated.ResourceVersion) + watcher, err := registry.WatchPredicate(testContext, matchPodName("foo"), podCreated.ResourceVersion) if err != nil { t.Fatalf("Unexpected error: %v", err) } @@ -960,18 +948,18 @@ func TestStoreWatch(t *testing.T) { noNamespaceContext := api.NewContext() table := map[string]struct { - generic.Matcher - context api.Context + selectPred *generic.SelectionPredicate + context api.Context }{ "single": { - Matcher: setMatcher{sets.NewString("foo")}, + selectPred: matchPodName("foo"), }, "multi": { - Matcher: setMatcher{sets.NewString("foo", "bar")}, + selectPred: matchPodName("foo", "bar"), }, "singleNoNamespace": { - Matcher: setMatcher{sets.NewString("foo")}, - context: noNamespaceContext, + selectPred: matchPodName("foo"), + context: noNamespaceContext, }, } @@ -989,7 +977,7 @@ func TestStoreWatch(t *testing.T) { } server, registry := NewTestGenericStoreRegistry(t) - wi, err := registry.WatchPredicate(ctx, m, "0") + wi, err := registry.WatchPredicate(ctx, m.selectPred, "0") if err != nil { t.Errorf("%v: unexpected error: %v", name, err) } else { @@ -1048,7 +1036,7 @@ func newTestGenericStoreRegistry(t *testing.T, hasCacheEnabled bool) (*etcdtesti return path.Join(podPrefix, id), nil }, ObjectNameFunc: func(obj runtime.Object) (string, error) { return obj.(*api.Pod).Name, nil }, - PredicateFunc: func(label labels.Selector, field fields.Selector) generic.Matcher { + PredicateFunc: func(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { return &generic.SelectionPredicate{ Label: label, Field: field, diff --git a/pkg/registry/horizontalpodautoscaler/strategy.go b/pkg/registry/horizontalpodautoscaler/strategy.go index b5889d27bb0..3ba063c0adf 100644 --- a/pkg/registry/horizontalpodautoscaler/strategy.go +++ b/pkg/registry/horizontalpodautoscaler/strategy.go @@ -85,10 +85,10 @@ func (autoscalerStrategy) AllowUnconditionalUpdate() bool { } func AutoscalerToSelectableFields(hpa *autoscaling.HorizontalPodAutoscaler) fields.Set { - return fields.Set{} + return nil } -func MatchAutoscaler(label labels.Selector, field fields.Selector) generic.Matcher { +func MatchAutoscaler(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { return &generic.SelectionPredicate{ Label: label, Field: field, diff --git a/pkg/registry/horizontalpodautoscaler/strategy_test.go b/pkg/registry/horizontalpodautoscaler/strategy_test.go index 12f38da1b6e..f5df8fa211b 100644 --- a/pkg/registry/horizontalpodautoscaler/strategy_test.go +++ b/pkg/registry/horizontalpodautoscaler/strategy_test.go @@ -23,14 +23,13 @@ import ( "k8s.io/kubernetes/pkg/api/testapi" apitesting "k8s.io/kubernetes/pkg/api/testing" "k8s.io/kubernetes/pkg/apis/autoscaling" - "k8s.io/kubernetes/pkg/labels" ) func TestSelectableFieldLabelConversions(t *testing.T) { apitesting.TestSelectableFieldLabelConversionsOfKind(t, testapi.Autoscaling.GroupVersion().String(), "Autoscaler", - labels.Set(AutoscalerToSelectableFields(&autoscaling.HorizontalPodAutoscaler{})), + AutoscalerToSelectableFields(&autoscaling.HorizontalPodAutoscaler{}), nil, ) } diff --git a/pkg/registry/ingress/strategy.go b/pkg/registry/ingress/strategy.go index a457844fb3e..5238ebe925f 100644 --- a/pkg/registry/ingress/strategy.go +++ b/pkg/registry/ingress/strategy.go @@ -105,7 +105,7 @@ func IngressToSelectableFields(ingress *extensions.Ingress) fields.Set { // MatchIngress is the filter used by the generic etcd backend to ingress // watch events from etcd to clients of the apiserver only interested in specific // labels/fields. -func MatchIngress(label labels.Selector, field fields.Selector) generic.Matcher { +func MatchIngress(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { return &generic.SelectionPredicate{ Label: label, Field: field, diff --git a/pkg/registry/ingress/strategy_test.go b/pkg/registry/ingress/strategy_test.go index b345bc06d7a..cc2494541f4 100644 --- a/pkg/registry/ingress/strategy_test.go +++ b/pkg/registry/ingress/strategy_test.go @@ -23,7 +23,6 @@ import ( "k8s.io/kubernetes/pkg/api/testapi" apitesting "k8s.io/kubernetes/pkg/api/testing" "k8s.io/kubernetes/pkg/apis/extensions" - "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/util/intstr" ) @@ -136,7 +135,7 @@ func TestSelectableFieldLabelConversions(t *testing.T) { apitesting.TestSelectableFieldLabelConversionsOfKind(t, testapi.Extensions.GroupVersion().String(), "Ingress", - labels.Set(IngressToSelectableFields(&extensions.Ingress{})), + IngressToSelectableFields(&extensions.Ingress{}), nil, ) } diff --git a/pkg/registry/job/strategy.go b/pkg/registry/job/strategy.go index e943f639230..a9769637379 100644 --- a/pkg/registry/job/strategy.go +++ b/pkg/registry/job/strategy.go @@ -166,7 +166,7 @@ func JobToSelectableFields(job *batch.Job) fields.Set { // MatchJob is the filter used by the generic etcd backend to route // watch events from etcd to clients of the apiserver only interested in specific // labels/fields. -func MatchJob(label labels.Selector, field fields.Selector) generic.Matcher { +func MatchJob(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { return &generic.SelectionPredicate{ Label: label, Field: field, diff --git a/pkg/registry/job/strategy_test.go b/pkg/registry/job/strategy_test.go index 638e5e63efa..8d52c30c29c 100644 --- a/pkg/registry/job/strategy_test.go +++ b/pkg/registry/job/strategy_test.go @@ -25,7 +25,6 @@ import ( apitesting "k8s.io/kubernetes/pkg/api/testing" "k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/apis/batch" - "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/types" ) @@ -226,7 +225,7 @@ func TestSelectableFieldLabelConversions(t *testing.T) { apitesting.TestSelectableFieldLabelConversionsOfKind(t, testapi.Extensions.GroupVersion().String(), "Job", - labels.Set(JobToSelectableFields(&batch.Job{})), + JobToSelectableFields(&batch.Job{}), nil, ) } diff --git a/pkg/registry/limitrange/strategy.go b/pkg/registry/limitrange/strategy.go index 4e36e4ae2d3..96fc19590da 100644 --- a/pkg/registry/limitrange/strategy.go +++ b/pkg/registry/limitrange/strategy.go @@ -75,7 +75,7 @@ func (limitrangeStrategy) AllowUnconditionalUpdate() bool { } func LimitRangeToSelectableFields(limitRange *api.LimitRange) fields.Set { - return fields.Set{} + return nil } func (limitrangeStrategy) Export(api.Context, runtime.Object, bool) error { @@ -85,7 +85,7 @@ func (limitrangeStrategy) Export(api.Context, runtime.Object, bool) error { return nil } -func MatchLimitRange(label labels.Selector, field fields.Selector) generic.Matcher { +func MatchLimitRange(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { return &generic.SelectionPredicate{ Label: label, Field: field, diff --git a/pkg/registry/limitrange/strategy_test.go b/pkg/registry/limitrange/strategy_test.go index 4c9a8465e7c..df26a551c7f 100644 --- a/pkg/registry/limitrange/strategy_test.go +++ b/pkg/registry/limitrange/strategy_test.go @@ -22,14 +22,13 @@ import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/testapi" apitesting "k8s.io/kubernetes/pkg/api/testing" - "k8s.io/kubernetes/pkg/labels" ) func TestSelectableFieldLabelConversions(t *testing.T) { apitesting.TestSelectableFieldLabelConversionsOfKind(t, testapi.Default.GroupVersion().String(), "LimitRange", - labels.Set(LimitRangeToSelectableFields(&api.LimitRange{})), + LimitRangeToSelectableFields(&api.LimitRange{}), nil, ) } diff --git a/pkg/registry/namespace/strategy.go b/pkg/registry/namespace/strategy.go index bb71d2056a2..5ef0441c18e 100644 --- a/pkg/registry/namespace/strategy.go +++ b/pkg/registry/namespace/strategy.go @@ -135,24 +135,27 @@ func (namespaceFinalizeStrategy) PrepareForUpdate(ctx api.Context, obj, old runt } // MatchNamespace returns a generic matcher for a given label and field selector. -func MatchNamespace(label labels.Selector, field fields.Selector) generic.Matcher { - return generic.MatcherFunc(func(obj runtime.Object) (bool, error) { - namespaceObj, ok := obj.(*api.Namespace) - if !ok { - return false, fmt.Errorf("not a namespace") - } - fields := NamespaceToSelectableFields(namespaceObj) - return label.Matches(labels.Set(namespaceObj.Labels)) && field.Matches(fields), nil - }) +func MatchNamespace(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { + return &generic.SelectionPredicate{ + Label: label, + Field: field, + GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) { + namespaceObj, ok := obj.(*api.Namespace) + if !ok { + return nil, nil, fmt.Errorf("not a namespace") + } + return labels.Set(namespaceObj.Labels), NamespaceToSelectableFields(namespaceObj), nil + }, + } } -// NamespaceToSelectableFields returns a label set that represents the object -func NamespaceToSelectableFields(namespace *api.Namespace) labels.Set { +// NamespaceToSelectableFields returns a field set that represents the object +func NamespaceToSelectableFields(namespace *api.Namespace) fields.Set { objectMetaFieldsSet := generic.ObjectMetaFieldsSet(namespace.ObjectMeta, false) specificFieldsSet := fields.Set{ "status.phase": string(namespace.Status.Phase), // This is a bug, but we need to support it for backward compatibility. "name": namespace.Name, } - return labels.Set(generic.MergeFieldsSets(objectMetaFieldsSet, specificFieldsSet)) + return generic.MergeFieldsSets(objectMetaFieldsSet, specificFieldsSet) } diff --git a/pkg/registry/networkpolicy/strategy.go b/pkg/registry/networkpolicy/strategy.go index c44cf32b78a..9a2da57c676 100644 --- a/pkg/registry/networkpolicy/strategy.go +++ b/pkg/registry/networkpolicy/strategy.go @@ -97,7 +97,7 @@ func NetworkPolicyToSelectableFields(networkPolicy *extensions.NetworkPolicy) fi // MatchNetworkPolicy is the filter used by the generic etcd backend to watch events // from etcd to clients of the apiserver only interested in specific labels/fields. -func MatchNetworkPolicy(label labels.Selector, field fields.Selector) generic.Matcher { +func MatchNetworkPolicy(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { return &generic.SelectionPredicate{ Label: label, Field: field, diff --git a/pkg/registry/node/strategy.go b/pkg/registry/node/strategy.go index c36b329ed43..532f5394c45 100644 --- a/pkg/registry/node/strategy.go +++ b/pkg/registry/node/strategy.go @@ -147,7 +147,7 @@ func NodeToSelectableFields(node *api.Node) fields.Set { } // MatchNode returns a generic matcher for a given label and field selector. -func MatchNode(label labels.Selector, field fields.Selector) generic.Matcher { +func MatchNode(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { return &generic.SelectionPredicate{ Label: label, Field: field, diff --git a/pkg/registry/node/strategy_test.go b/pkg/registry/node/strategy_test.go index 18757f5b461..ea51666a210 100644 --- a/pkg/registry/node/strategy_test.go +++ b/pkg/registry/node/strategy_test.go @@ -51,7 +51,7 @@ func TestSelectableFieldLabelConversions(t *testing.T) { apitesting.TestSelectableFieldLabelConversionsOfKind(t, testapi.Default.GroupVersion().String(), "Node", - labels.Set(NodeToSelectableFields(&api.Node{})), + NodeToSelectableFields(&api.Node{}), nil, ) } diff --git a/pkg/registry/persistentvolume/strategy.go b/pkg/registry/persistentvolume/strategy.go index b8e542c3c21..4b5e3118897 100644 --- a/pkg/registry/persistentvolume/strategy.go +++ b/pkg/registry/persistentvolume/strategy.go @@ -95,23 +95,26 @@ func (persistentvolumeStatusStrategy) ValidateUpdate(ctx api.Context, obj, old r } // MatchPersistentVolume returns a generic matcher for a given label and field selector. -func MatchPersistentVolumes(label labels.Selector, field fields.Selector) generic.Matcher { - return generic.MatcherFunc(func(obj runtime.Object) (bool, error) { - persistentvolumeObj, ok := obj.(*api.PersistentVolume) - if !ok { - return false, fmt.Errorf("not a persistentvolume") - } - fields := PersistentVolumeToSelectableFields(persistentvolumeObj) - return label.Matches(labels.Set(persistentvolumeObj.Labels)) && field.Matches(fields), nil - }) +func MatchPersistentVolumes(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { + return &generic.SelectionPredicate{ + Label: label, + Field: field, + GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) { + persistentvolumeObj, ok := obj.(*api.PersistentVolume) + if !ok { + return nil, nil, fmt.Errorf("not a persistentvolume") + } + return labels.Set(persistentvolumeObj.Labels), PersistentVolumeToSelectableFields(persistentvolumeObj), nil + }, + } } -// PersistentVolumeToSelectableFields returns a label set that represents the object -func PersistentVolumeToSelectableFields(persistentvolume *api.PersistentVolume) labels.Set { +// PersistentVolumeToSelectableFields returns a field set that represents the object +func PersistentVolumeToSelectableFields(persistentvolume *api.PersistentVolume) fields.Set { objectMetaFieldsSet := generic.ObjectMetaFieldsSet(persistentvolume.ObjectMeta, false) specificFieldsSet := fields.Set{ // This is a bug, but we need to support it for backward compatibility. "name": persistentvolume.Name, } - return labels.Set(generic.MergeFieldsSets(objectMetaFieldsSet, specificFieldsSet)) + return generic.MergeFieldsSets(objectMetaFieldsSet, specificFieldsSet) } diff --git a/pkg/registry/persistentvolumeclaim/strategy.go b/pkg/registry/persistentvolumeclaim/strategy.go index 0d88db9361c..0b259f04cc0 100644 --- a/pkg/registry/persistentvolumeclaim/strategy.go +++ b/pkg/registry/persistentvolumeclaim/strategy.go @@ -95,23 +95,26 @@ func (persistentvolumeclaimStatusStrategy) ValidateUpdate(ctx api.Context, obj, } // MatchPersistentVolumeClaim returns a generic matcher for a given label and field selector. -func MatchPersistentVolumeClaim(label labels.Selector, field fields.Selector) generic.Matcher { - return generic.MatcherFunc(func(obj runtime.Object) (bool, error) { - persistentvolumeclaimObj, ok := obj.(*api.PersistentVolumeClaim) - if !ok { - return false, fmt.Errorf("not a persistentvolumeclaim") - } - fields := PersistentVolumeClaimToSelectableFields(persistentvolumeclaimObj) - return label.Matches(labels.Set(persistentvolumeclaimObj.Labels)) && field.Matches(fields), nil - }) +func MatchPersistentVolumeClaim(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { + return &generic.SelectionPredicate{ + Label: label, + Field: field, + GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) { + persistentvolumeclaimObj, ok := obj.(*api.PersistentVolumeClaim) + if !ok { + return nil, nil, fmt.Errorf("not a persistentvolumeclaim") + } + return labels.Set(persistentvolumeclaimObj.Labels), PersistentVolumeClaimToSelectableFields(persistentvolumeclaimObj), nil + }, + } } -// PersistentVolumeClaimToSelectableFields returns a label set that represents the object -func PersistentVolumeClaimToSelectableFields(persistentvolumeclaim *api.PersistentVolumeClaim) labels.Set { +// PersistentVolumeClaimToSelectableFields returns a field set that represents the object +func PersistentVolumeClaimToSelectableFields(persistentvolumeclaim *api.PersistentVolumeClaim) fields.Set { objectMetaFieldsSet := generic.ObjectMetaFieldsSet(persistentvolumeclaim.ObjectMeta, true) specificFieldsSet := fields.Set{ // This is a bug, but we need to support it for backward compatibility. "name": persistentvolumeclaim.Name, } - return labels.Set(generic.MergeFieldsSets(objectMetaFieldsSet, specificFieldsSet)) + return generic.MergeFieldsSets(objectMetaFieldsSet, specificFieldsSet) } diff --git a/pkg/registry/petset/strategy.go b/pkg/registry/petset/strategy.go index 2365622e80d..2ff0ada8e76 100644 --- a/pkg/registry/petset/strategy.go +++ b/pkg/registry/petset/strategy.go @@ -103,7 +103,7 @@ func PetSetToSelectableFields(petSet *apps.PetSet) fields.Set { // MatchPetSet is the filter used by the generic etcd backend to watch events // from etcd to clients of the apiserver only interested in specific labels/fields. -func MatchPetSet(label labels.Selector, field fields.Selector) generic.Matcher { +func MatchPetSet(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { return &generic.SelectionPredicate{ Label: label, Field: field, diff --git a/pkg/registry/pod/strategy.go b/pkg/registry/pod/strategy.go index b3a873c63f2..35199f0c44c 100644 --- a/pkg/registry/pod/strategy.go +++ b/pkg/registry/pod/strategy.go @@ -155,7 +155,7 @@ func (podStatusStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object } // MatchPod returns a generic matcher for a given label and field selector. -func MatchPod(label labels.Selector, field fields.Selector) generic.Matcher { +func MatchPod(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { return &generic.SelectionPredicate{ Label: label, Field: field, diff --git a/pkg/registry/pod/strategy_test.go b/pkg/registry/pod/strategy_test.go index c0c42f6d6d0..d76f31af138 100644 --- a/pkg/registry/pod/strategy_test.go +++ b/pkg/registry/pod/strategy_test.go @@ -252,7 +252,7 @@ func TestSelectableFieldLabelConversions(t *testing.T) { apitesting.TestSelectableFieldLabelConversionsOfKind(t, testapi.Default.GroupVersion().String(), "Pod", - labels.Set(PodToSelectableFields(&api.Pod{})), + PodToSelectableFields(&api.Pod{}), nil, ) } diff --git a/pkg/registry/poddisruptionbudget/strategy.go b/pkg/registry/poddisruptionbudget/strategy.go index aea297dfccf..450fb302a8f 100644 --- a/pkg/registry/poddisruptionbudget/strategy.go +++ b/pkg/registry/poddisruptionbudget/strategy.go @@ -102,7 +102,7 @@ func PodDisruptionBudgetToSelectableFields(podDisruptionBudget *policy.PodDisrup // MatchPodDisruptionBudget is the filter used by the generic etcd backend to watch events // from etcd to clients of the apiserver only interested in specific labels/fields. -func MatchPodDisruptionBudget(label labels.Selector, field fields.Selector) generic.Matcher { +func MatchPodDisruptionBudget(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { return &generic.SelectionPredicate{ Label: label, Field: field, diff --git a/pkg/registry/podsecuritypolicy/strategy.go b/pkg/registry/podsecuritypolicy/strategy.go index f3f54b86abf..4bc4bba8c23 100644 --- a/pkg/registry/podsecuritypolicy/strategy.go +++ b/pkg/registry/podsecuritypolicy/strategy.go @@ -74,7 +74,7 @@ func (strategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.E } // Matcher returns a generic matcher for a given label and field selector. -func MatchPodSecurityPolicy(label labels.Selector, field fields.Selector) generic.Matcher { +func MatchPodSecurityPolicy(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { return &generic.SelectionPredicate{ Label: label, Field: field, diff --git a/pkg/registry/podtemplate/strategy.go b/pkg/registry/podtemplate/strategy.go index d0759b324e6..4478928004e 100644 --- a/pkg/registry/podtemplate/strategy.go +++ b/pkg/registry/podtemplate/strategy.go @@ -83,10 +83,10 @@ func (podTemplateStrategy) Export(ctx api.Context, obj runtime.Object, exact boo } func PodTemplateToSelectableFields(podTemplate *api.PodTemplate) fields.Set { - return fields.Set{} + return nil } -func MatchPodTemplate(label labels.Selector, field fields.Selector) generic.Matcher { +func MatchPodTemplate(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { return &generic.SelectionPredicate{ Label: label, Field: field, diff --git a/pkg/registry/podtemplate/strategy_test.go b/pkg/registry/podtemplate/strategy_test.go index 5622310e775..6e8b99b9709 100644 --- a/pkg/registry/podtemplate/strategy_test.go +++ b/pkg/registry/podtemplate/strategy_test.go @@ -22,14 +22,13 @@ import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/testapi" apitesting "k8s.io/kubernetes/pkg/api/testing" - "k8s.io/kubernetes/pkg/labels" ) func TestSelectableFieldLabelConversions(t *testing.T) { apitesting.TestSelectableFieldLabelConversionsOfKind(t, testapi.Default.GroupVersion().String(), "PodTemplate", - labels.Set(PodTemplateToSelectableFields(&api.PodTemplate{})), + PodTemplateToSelectableFields(&api.PodTemplate{}), nil, ) } diff --git a/pkg/registry/replicaset/strategy.go b/pkg/registry/replicaset/strategy.go index 824b758f6d0..a8adc95cdfc 100644 --- a/pkg/registry/replicaset/strategy.go +++ b/pkg/registry/replicaset/strategy.go @@ -114,7 +114,7 @@ func ReplicaSetToSelectableFields(rs *extensions.ReplicaSet) fields.Set { // MatchReplicaSet is the filter used by the generic etcd backend to route // watch events from etcd to clients of the apiserver only interested in specific // labels/fields. -func MatchReplicaSet(label labels.Selector, field fields.Selector) generic.Matcher { +func MatchReplicaSet(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { return &generic.SelectionPredicate{ Label: label, Field: field, diff --git a/pkg/registry/resourcequota/strategy.go b/pkg/registry/resourcequota/strategy.go index 6b467bbd84f..1e6051f875f 100644 --- a/pkg/registry/resourcequota/strategy.go +++ b/pkg/registry/resourcequota/strategy.go @@ -98,18 +98,21 @@ func (resourcequotaStatusStrategy) ValidateUpdate(ctx api.Context, obj, old runt } // MatchResourceQuota returns a generic matcher for a given label and field selector. -func MatchResourceQuota(label labels.Selector, field fields.Selector) generic.Matcher { - return generic.MatcherFunc(func(obj runtime.Object) (bool, error) { - resourcequotaObj, ok := obj.(*api.ResourceQuota) - if !ok { - return false, fmt.Errorf("not a resourcequota") - } - fields := ResourceQuotaToSelectableFields(resourcequotaObj) - return label.Matches(labels.Set(resourcequotaObj.Labels)) && field.Matches(fields), nil - }) +func MatchResourceQuota(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { + return &generic.SelectionPredicate{ + Label: label, + Field: field, + GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) { + resourcequotaObj, ok := obj.(*api.ResourceQuota) + if !ok { + return nil, nil, fmt.Errorf("not a resourcequota") + } + return labels.Set(resourcequotaObj.Labels), ResourceQuotaToSelectableFields(resourcequotaObj), nil + }, + } } -// ResourceQuotaToSelectableFields returns a label set that represents the object -func ResourceQuotaToSelectableFields(resourcequota *api.ResourceQuota) labels.Set { - return labels.Set(generic.ObjectMetaFieldsSet(resourcequota.ObjectMeta, true)) +// ResourceQuotaToSelectableFields returns a field set that represents the object +func ResourceQuotaToSelectableFields(resourcequota *api.ResourceQuota) fields.Set { + return generic.ObjectMetaFieldsSet(resourcequota.ObjectMeta, true) } diff --git a/pkg/registry/role/strategy.go b/pkg/registry/role/strategy.go index e15a0ad5d5e..02d30e36a4d 100644 --- a/pkg/registry/role/strategy.go +++ b/pkg/registry/role/strategy.go @@ -102,18 +102,21 @@ func (s strategy) Export(ctx api.Context, obj runtime.Object, exact bool) error } // Matcher returns a generic matcher for a given label and field selector. -func Matcher(label labels.Selector, field fields.Selector) generic.Matcher { - return generic.MatcherFunc(func(obj runtime.Object) (bool, error) { - sa, ok := obj.(*rbac.Role) - if !ok { - return false, fmt.Errorf("not a Role") - } - fields := SelectableFields(sa) - return label.Matches(labels.Set(sa.Labels)) && field.Matches(fields), nil - }) +func Matcher(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { + return &generic.SelectionPredicate{ + Label: label, + Field: field, + GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) { + role, ok := obj.(*rbac.Role) + if !ok { + return nil, nil, fmt.Errorf("not a Role") + } + return labels.Set(role.Labels), SelectableFields(role), nil + }, + } } -// SelectableFields returns a label set that can be used for filter selection -func SelectableFields(obj *rbac.Role) labels.Set { - return labels.Set{} +// SelectableFields returns a field set that can be used for filter selection +func SelectableFields(obj *rbac.Role) fields.Set { + return nil } diff --git a/pkg/registry/rolebinding/strategy.go b/pkg/registry/rolebinding/strategy.go index 7c438900500..2aca8190a23 100644 --- a/pkg/registry/rolebinding/strategy.go +++ b/pkg/registry/rolebinding/strategy.go @@ -102,18 +102,21 @@ func (s strategy) Export(ctx api.Context, obj runtime.Object, exact bool) error } // Matcher returns a generic matcher for a given label and field selector. -func Matcher(label labels.Selector, field fields.Selector) generic.Matcher { - return generic.MatcherFunc(func(obj runtime.Object) (bool, error) { - sa, ok := obj.(*rbac.RoleBinding) - if !ok { - return false, fmt.Errorf("not a RoleBinding") - } - fields := SelectableFields(sa) - return label.Matches(labels.Set(sa.Labels)) && field.Matches(fields), nil - }) +func Matcher(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { + return &generic.SelectionPredicate{ + Label: label, + Field: field, + GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) { + roleBinding, ok := obj.(*rbac.RoleBinding) + if !ok { + return nil, nil, fmt.Errorf("not a RoleBinding") + } + return labels.Set(roleBinding.Labels), SelectableFields(roleBinding), nil + }, + } } -// SelectableFields returns a label set that can be used for filter selection -func SelectableFields(obj *rbac.RoleBinding) labels.Set { - return labels.Set{} +// SelectableFields returns a field set that can be used for filter selection +func SelectableFields(obj *rbac.RoleBinding) fields.Set { + return nil } diff --git a/pkg/registry/scheduledjob/strategy.go b/pkg/registry/scheduledjob/strategy.go index 6cd77559ef3..d8db976f827 100644 --- a/pkg/registry/scheduledjob/strategy.go +++ b/pkg/registry/scheduledjob/strategy.go @@ -104,7 +104,7 @@ func ScheduledJobToSelectableFields(scheduledJob *batch.ScheduledJob) fields.Set // MatchScheduledJob is the filter used by the generic etcd backend to route // watch events from etcd to clients of the apiserver only interested in specific // labels/fields. -func MatchScheduledJob(label labels.Selector, field fields.Selector) generic.Matcher { +func MatchScheduledJob(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { return &generic.SelectionPredicate{ Label: label, Field: field, diff --git a/pkg/registry/scheduledjob/strategy_test.go b/pkg/registry/scheduledjob/strategy_test.go index 35fa05667bf..8ef27c402df 100644 --- a/pkg/registry/scheduledjob/strategy_test.go +++ b/pkg/registry/scheduledjob/strategy_test.go @@ -23,7 +23,6 @@ import ( apitesting "k8s.io/kubernetes/pkg/api/testing" "k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/apis/batch" - "k8s.io/kubernetes/pkg/labels" ) func newBool(a bool) *bool { @@ -168,7 +167,7 @@ func TestSelectableFieldLabelConversions(t *testing.T) { apitesting.TestSelectableFieldLabelConversionsOfKind(t, "batch/v2alpha1", "ScheduledJob", - labels.Set(ScheduledJobToSelectableFields(&batch.ScheduledJob{})), + ScheduledJobToSelectableFields(&batch.ScheduledJob{}), nil, ) } diff --git a/pkg/registry/secret/strategy.go b/pkg/registry/secret/strategy.go index 2101e3b511d..8663f5109eb 100644 --- a/pkg/registry/secret/strategy.go +++ b/pkg/registry/secret/strategy.go @@ -94,22 +94,25 @@ func (s strategy) Export(ctx api.Context, obj runtime.Object, exact bool) error } // Matcher returns a generic matcher for a given label and field selector. -func Matcher(label labels.Selector, field fields.Selector) generic.Matcher { - return generic.MatcherFunc(func(obj runtime.Object) (bool, error) { - sa, ok := obj.(*api.Secret) - if !ok { - return false, fmt.Errorf("not a secret") - } - fields := SelectableFields(sa) - return label.Matches(labels.Set(sa.Labels)) && field.Matches(fields), nil - }) +func Matcher(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { + return &generic.SelectionPredicate{ + Label: label, + Field: field, + GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) { + secret, ok := obj.(*api.Secret) + if !ok { + return nil, nil, fmt.Errorf("not a secret") + } + return labels.Set(secret.Labels), SelectableFields(secret), nil + }, + } } -// SelectableFields returns a label set that can be used for filter selection -func SelectableFields(obj *api.Secret) labels.Set { +// SelectableFields returns a field set that can be used for filter selection +func SelectableFields(obj *api.Secret) fields.Set { objectMetaFieldsSet := generic.ObjectMetaFieldsSet(obj.ObjectMeta, true) secretSpecificFieldsSet := fields.Set{ "type": string(obj.Type), } - return labels.Set(generic.MergeFieldsSets(objectMetaFieldsSet, secretSpecificFieldsSet)) + return generic.MergeFieldsSets(objectMetaFieldsSet, secretSpecificFieldsSet) } diff --git a/pkg/registry/service/strategy.go b/pkg/registry/service/strategy.go index ea1799da010..8fe1e3da02d 100644 --- a/pkg/registry/service/strategy.go +++ b/pkg/registry/service/strategy.go @@ -100,7 +100,7 @@ func (svcStrategy) Export(ctx api.Context, obj runtime.Object, exact bool) error return nil } -func MatchServices(label labels.Selector, field fields.Selector) generic.Matcher { +func MatchServices(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { return &generic.SelectionPredicate{ Label: label, Field: field, diff --git a/pkg/registry/service/strategy_test.go b/pkg/registry/service/strategy_test.go index c349309726c..df03927c87b 100644 --- a/pkg/registry/service/strategy_test.go +++ b/pkg/registry/service/strategy_test.go @@ -25,7 +25,6 @@ import ( "k8s.io/kubernetes/pkg/api/rest" "k8s.io/kubernetes/pkg/api/testapi" apitesting "k8s.io/kubernetes/pkg/api/testing" - "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/util/intstr" ) @@ -216,7 +215,7 @@ func TestSelectableFieldLabelConversions(t *testing.T) { apitesting.TestSelectableFieldLabelConversionsOfKind(t, testapi.Default.GroupVersion().String(), "Service", - labels.Set(ServiceToSelectableFields(&api.Service{})), + ServiceToSelectableFields(&api.Service{}), nil, ) } diff --git a/pkg/registry/serviceaccount/strategy.go b/pkg/registry/serviceaccount/strategy.go index c0f9cd4bb77..dc10c80e844 100644 --- a/pkg/registry/serviceaccount/strategy.go +++ b/pkg/registry/serviceaccount/strategy.go @@ -77,18 +77,21 @@ func (strategy) AllowUnconditionalUpdate() bool { } // Matcher returns a generic matcher for a given label and field selector. -func Matcher(label labels.Selector, field fields.Selector) generic.Matcher { - return generic.MatcherFunc(func(obj runtime.Object) (bool, error) { - sa, ok := obj.(*api.ServiceAccount) - if !ok { - return false, fmt.Errorf("not a serviceaccount") - } - fields := SelectableFields(sa) - return label.Matches(labels.Set(sa.Labels)) && field.Matches(fields), nil - }) +func Matcher(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { + return &generic.SelectionPredicate{ + Label: label, + Field: field, + GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) { + sa, ok := obj.(*api.ServiceAccount) + if !ok { + return nil, nil, fmt.Errorf("not a serviceaccount") + } + return labels.Set(sa.Labels), SelectableFields(sa), nil + }, + } } -// SelectableFields returns a label set that represents the object -func SelectableFields(obj *api.ServiceAccount) labels.Set { - return labels.Set(generic.ObjectMetaFieldsSet(obj.ObjectMeta, true)) +// SelectableFields returns a field set that represents the object +func SelectableFields(obj *api.ServiceAccount) fields.Set { + return generic.ObjectMetaFieldsSet(obj.ObjectMeta, true) } diff --git a/pkg/registry/storageclass/strategy.go b/pkg/registry/storageclass/strategy.go index 21c1b156ce7..6ee3ef8b827 100644 --- a/pkg/registry/storageclass/strategy.go +++ b/pkg/registry/storageclass/strategy.go @@ -77,7 +77,7 @@ func (storageClassStrategy) AllowUnconditionalUpdate() bool { } // MatchStorageClass returns a generic matcher for a given label and field selector. -func MatchStorageClasses(label labels.Selector, field fields.Selector) generic.Matcher { +func MatchStorageClasses(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { return &generic.SelectionPredicate{ Label: label, Field: field, diff --git a/pkg/registry/thirdpartyresource/strategy.go b/pkg/registry/thirdpartyresource/strategy.go index 10162c6a25f..39b20a874fa 100644 --- a/pkg/registry/thirdpartyresource/strategy.go +++ b/pkg/registry/thirdpartyresource/strategy.go @@ -78,18 +78,21 @@ func (strategy) AllowUnconditionalUpdate() bool { } // Matcher returns a generic matcher for a given label and field selector. -func Matcher(label labels.Selector, field fields.Selector) generic.Matcher { - return generic.MatcherFunc(func(obj runtime.Object) (bool, error) { - sa, ok := obj.(*extensions.ThirdPartyResource) - if !ok { - return false, fmt.Errorf("not a ThirdPartyResource") - } - fields := SelectableFields(sa) - return label.Matches(labels.Set(sa.Labels)) && field.Matches(fields), nil - }) +func Matcher(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { + return &generic.SelectionPredicate{ + Label: label, + Field: field, + GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) { + tpr, ok := obj.(*extensions.ThirdPartyResource) + if !ok { + return nil, nil, fmt.Errorf("not a ThirdPartyResource") + } + return labels.Set(tpr.Labels), SelectableFields(tpr), nil + }, + } } -// SelectableFields returns a label set that can be used for filter selection -func SelectableFields(obj *extensions.ThirdPartyResource) labels.Set { - return labels.Set{} +// SelectableFields returns a field set that can be used for filter selection +func SelectableFields(obj *extensions.ThirdPartyResource) fields.Set { + return nil } diff --git a/pkg/registry/thirdpartyresourcedata/strategy.go b/pkg/registry/thirdpartyresourcedata/strategy.go index f4afad0a996..5ed76ed45ac 100644 --- a/pkg/registry/thirdpartyresourcedata/strategy.go +++ b/pkg/registry/thirdpartyresourcedata/strategy.go @@ -75,18 +75,21 @@ func (strategy) AllowUnconditionalUpdate() bool { } // Matcher returns a generic matcher for a given label and field selector. -func Matcher(label labels.Selector, field fields.Selector) generic.Matcher { - return generic.MatcherFunc(func(obj runtime.Object) (bool, error) { - sa, ok := obj.(*extensions.ThirdPartyResourceData) - if !ok { - return false, fmt.Errorf("not a ThirdPartyResourceData") - } - fields := SelectableFields(sa) - return label.Matches(labels.Set(sa.Labels)) && field.Matches(fields), nil - }) +func Matcher(label labels.Selector, field fields.Selector) *generic.SelectionPredicate { + return &generic.SelectionPredicate{ + Label: label, + Field: field, + GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) { + tprd, ok := obj.(*extensions.ThirdPartyResourceData) + if !ok { + return nil, nil, fmt.Errorf("not a ThirdPartyResourceData") + } + return labels.Set(tprd.Labels), SelectableFields(tprd), nil + }, + } } -// SelectableFields returns a label set that can be used for filter selection -func SelectableFields(obj *extensions.ThirdPartyResourceData) labels.Set { - return labels.Set{} +// SelectableFields returns a field set that can be used for filter selection +func SelectableFields(obj *extensions.ThirdPartyResourceData) fields.Set { + return nil }