Merge pull request #30529 from hongchaodeng/r1

Automatic merge from submit-queue

change all PredicateFunc to use SelectionPredicate

What?
- This PR changes all PredicateFunc in registry to return SelectionPredicate instead of Matcher interface.

Why?
- We want to pass SelectionPredicate to storage layer. Matcher interface did not expose enough information for indexing.
This commit is contained in:
Kubernetes Submit Queue 2016-08-20 00:24:40 -07:00 committed by GitHub
commit 5caf74c517
58 changed files with 299 additions and 322 deletions

View File

@ -17,6 +17,8 @@ limitations under the License.
package rest package rest
import ( import (
"fmt"
"k8s.io/kubernetes/cmd/libs/go2idl/client-gen/test_apis/testgroup.k8s.io" "k8s.io/kubernetes/cmd/libs/go2idl/client-gen/test_apis/testgroup.k8s.io"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/fields" "k8s.io/kubernetes/pkg/fields"
@ -59,8 +61,18 @@ func NewREST(config *storagebackend.Config, storageDecorator generic.StorageDeco
return obj.(*testgroup.TestType).Name, nil return obj.(*testgroup.TestType).Name, nil
}, },
// Used to match objects based on labels/fields for list. // Used to match objects based on labels/fields for list.
PredicateFunc: func(label labels.Selector, field fields.Selector) generic.Matcher { PredicateFunc: func(label labels.Selector, field fields.Selector) *generic.SelectionPredicate {
return generic.MatcherFunc(nil) 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, Storage: storageInterface,
} }

View File

@ -44,7 +44,7 @@ func ClusterToSelectableFields(cluster *federation.Cluster) fields.Set {
return generic.ObjectMetaFieldsSet(cluster.ObjectMeta, false) 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{ return &generic.SelectionPredicate{
Label: label, Label: label,
Field: field, Field: field,

View File

@ -157,7 +157,7 @@ func TestSelectableFieldLabelConversions(t *testing.T) {
apitesting.TestSelectableFieldLabelConversionsOfKind(t, apitesting.TestSelectableFieldLabelConversionsOfKind(t,
testapi.Federation.GroupVersion().String(), testapi.Federation.GroupVersion().String(),
"Cluster", "Cluster",
labels.Set(ClusterToSelectableFields(&federation.Cluster{})), ClusterToSelectableFields(&federation.Cluster{}),
nil, nil,
) )
} }

View File

@ -20,14 +20,14 @@ import (
"testing" "testing"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/fields"
) )
// TestSelectableFieldLabelConversions verifies that given resource have field // TestSelectableFieldLabelConversions verifies that given resource have field
// label conversion defined for each its selectable field. // label conversion defined for each its selectable field.
// fields contains selectable fields of the resource. // fields contains selectable fields of the resource.
// labelMap maps deprecated labels to their canonical names. // 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{ badFieldLabels := []string{
"name", "name",
".name", ".name",

View File

@ -62,7 +62,7 @@ func NewREST(opts generic.RESTOptions) (*REST, *StatusREST, *ApprovalREST) {
ObjectNameFunc: func(obj runtime.Object) (string, error) { ObjectNameFunc: func(obj runtime.Object) (string, error) {
return obj.(*certificates.CertificateSigningRequest).Name, nil 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) return csrregistry.Matcher(label, field)
}, },
QualifiedResource: certificates.Resource("certificatesigningrequests"), QualifiedResource: certificates.Resource("certificatesigningrequests"),

View File

@ -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. // Matcher returns a generic matcher for a given label and field selector.
func Matcher(label labels.Selector, field fields.Selector) generic.Matcher { func Matcher(label labels.Selector, field fields.Selector) *generic.SelectionPredicate {
return generic.MatcherFunc(func(obj runtime.Object) (bool, error) { return &generic.SelectionPredicate{
sa, ok := obj.(*certificates.CertificateSigningRequest) Label: label,
if !ok { Field: field,
return false, fmt.Errorf("not a CertificateSigningRequest") GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) {
} sa, ok := obj.(*certificates.CertificateSigningRequest)
fields := SelectableFields(sa) if !ok {
return label.Matches(labels.Set(sa.Labels)) && field.Matches(fields), nil 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 // SelectableFields returns a field set that can be used for filter selection
func SelectableFields(obj *certificates.CertificateSigningRequest) labels.Set { func SelectableFields(obj *certificates.CertificateSigningRequest) fields.Set {
return labels.Set{} return nil
} }

View File

@ -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. // Matcher returns a generic matcher for a given label and field selector.
func Matcher(label labels.Selector, field fields.Selector) generic.Matcher { func Matcher(label labels.Selector, field fields.Selector) *generic.SelectionPredicate {
return generic.MatcherFunc(func(obj runtime.Object) (bool, error) { return &generic.SelectionPredicate{
sa, ok := obj.(*rbac.ClusterRole) Label: label,
if !ok { Field: field,
return false, fmt.Errorf("not a ClusterRole") GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) {
} role, ok := obj.(*rbac.ClusterRole)
fields := SelectableFields(sa) if !ok {
return label.Matches(labels.Set(sa.Labels)) && field.Matches(fields), nil 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 // SelectableFields returns a field set that can be used for filter selection
func SelectableFields(obj *rbac.ClusterRole) labels.Set { func SelectableFields(obj *rbac.ClusterRole) fields.Set {
return labels.Set{} return nil
} }

View File

@ -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. // Matcher returns a generic matcher for a given label and field selector.
func Matcher(label labels.Selector, field fields.Selector) generic.Matcher { func Matcher(label labels.Selector, field fields.Selector) *generic.SelectionPredicate {
return generic.MatcherFunc(func(obj runtime.Object) (bool, error) { return &generic.SelectionPredicate{
sa, ok := obj.(*rbac.ClusterRoleBinding) Label: label,
if !ok { Field: field,
return false, fmt.Errorf("not a ClusterRoleBinding") GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) {
} roleBinding, ok := obj.(*rbac.ClusterRoleBinding)
fields := SelectableFields(sa) if !ok {
return label.Matches(labels.Set(sa.Labels)) && field.Matches(fields), nil 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 // SelectableFields returns a field set that can be used for filter selection
func SelectableFields(obj *rbac.ClusterRoleBinding) labels.Set { func SelectableFields(obj *rbac.ClusterRoleBinding) fields.Set {
return labels.Set{} return nil
} }

View File

@ -88,7 +88,7 @@ func ConfigMapToSelectableFields(cfg *api.ConfigMap) fields.Set {
} }
// MatchConfigMap returns a generic matcher for a given label and field selector. // 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{ return &generic.SelectionPredicate{
Label: label, Label: label,
Field: field, Field: field,

View File

@ -22,7 +22,6 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/api/testapi"
apitesting "k8s.io/kubernetes/pkg/api/testing" apitesting "k8s.io/kubernetes/pkg/api/testing"
"k8s.io/kubernetes/pkg/labels"
) )
func TestConfigMapStrategy(t *testing.T) { func TestConfigMapStrategy(t *testing.T) {
@ -74,7 +73,7 @@ func TestSelectableFieldLabelConversions(t *testing.T) {
apitesting.TestSelectableFieldLabelConversionsOfKind(t, apitesting.TestSelectableFieldLabelConversionsOfKind(t,
testapi.Default.GroupVersion().String(), testapi.Default.GroupVersion().String(),
"ConfigMap", "ConfigMap",
labels.Set(ConfigMapToSelectableFields(&api.ConfigMap{})), ConfigMapToSelectableFields(&api.ConfigMap{}),
nil, nil,
) )
} }

View File

@ -113,7 +113,7 @@ func ControllerToSelectableFields(controller *api.ReplicationController) fields.
// MatchController is the filter used by the generic etcd backend to route // 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 // watch events from etcd to clients of the apiserver only interested in specific
// labels/fields. // 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{ return &generic.SelectionPredicate{
Label: label, Label: label,
Field: field, Field: field,

View File

@ -22,7 +22,6 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/api/testapi"
apitesting "k8s.io/kubernetes/pkg/api/testing" apitesting "k8s.io/kubernetes/pkg/api/testing"
"k8s.io/kubernetes/pkg/labels"
) )
func TestControllerStrategy(t *testing.T) { func TestControllerStrategy(t *testing.T) {
@ -146,7 +145,7 @@ func TestSelectableFieldLabelConversions(t *testing.T) {
apitesting.TestSelectableFieldLabelConversionsOfKind(t, apitesting.TestSelectableFieldLabelConversionsOfKind(t,
testapi.Default.GroupVersion().String(), testapi.Default.GroupVersion().String(),
"ReplicationController", "ReplicationController",
labels.Set(ControllerToSelectableFields(&api.ReplicationController{})), ControllerToSelectableFields(&api.ReplicationController{}),
nil, nil,
) )
} }

View File

@ -112,7 +112,7 @@ func DaemonSetToSelectableFields(daemon *extensions.DaemonSet) fields.Set {
// MatchSetDaemon is the filter used by the generic etcd backend to route // 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 // watch events from etcd to clients of the apiserver only interested in specific
// labels/fields. // 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{ return &generic.SelectionPredicate{
Label: label, Label: label,
Field: field, Field: field,

View File

@ -23,14 +23,13 @@ import (
"k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/api/testapi"
apitesting "k8s.io/kubernetes/pkg/api/testing" apitesting "k8s.io/kubernetes/pkg/api/testing"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/labels"
) )
func TestSelectableFieldLabelConversions(t *testing.T) { func TestSelectableFieldLabelConversions(t *testing.T) {
apitesting.TestSelectableFieldLabelConversionsOfKind(t, apitesting.TestSelectableFieldLabelConversionsOfKind(t,
testapi.Extensions.GroupVersion().String(), testapi.Extensions.GroupVersion().String(),
"DaemonSet", "DaemonSet",
labels.Set(DaemonSetToSelectableFields(&extensions.DaemonSet{})), DaemonSetToSelectableFields(&extensions.DaemonSet{}),
nil, nil,
) )
} }

View File

@ -118,7 +118,7 @@ func DeploymentToSelectableFields(deployment *extensions.Deployment) fields.Set
// MatchDeployment is the filter used by the generic etcd backend to route // 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 // watch events from etcd to clients of the apiserver only interested in specific
// labels/fields. // 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{ return &generic.SelectionPredicate{
Label: label, Label: label,
Field: field, Field: field,

View File

@ -24,7 +24,6 @@ import (
"k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/api/testapi"
apitesting "k8s.io/kubernetes/pkg/api/testing" apitesting "k8s.io/kubernetes/pkg/api/testing"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
) )
@ -32,7 +31,7 @@ func TestSelectableFieldLabelConversions(t *testing.T) {
apitesting.TestSelectableFieldLabelConversionsOfKind(t, apitesting.TestSelectableFieldLabelConversionsOfKind(t,
testapi.Extensions.GroupVersion().String(), testapi.Extensions.GroupVersion().String(),
"Deployment", "Deployment",
labels.Set(DeploymentToSelectableFields(&extensions.Deployment{})), DeploymentToSelectableFields(&extensions.Deployment{}),
nil, nil,
) )
} }

View File

@ -79,7 +79,7 @@ func (endpointsStrategy) AllowUnconditionalUpdate() bool {
} }
// MatchEndpoints returns a generic matcher for a given label and field selector. // 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} return &generic.SelectionPredicate{Label: label, Field: field, GetAttrs: EndpointsAttributes}
} }

View File

@ -22,7 +22,6 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/api/testapi"
apitesting "k8s.io/kubernetes/pkg/api/testing" apitesting "k8s.io/kubernetes/pkg/api/testing"
"k8s.io/kubernetes/pkg/labels"
) )
func TestSelectableFieldLabelConversions(t *testing.T) { func TestSelectableFieldLabelConversions(t *testing.T) {
@ -33,7 +32,7 @@ func TestSelectableFieldLabelConversions(t *testing.T) {
apitesting.TestSelectableFieldLabelConversionsOfKind(t, apitesting.TestSelectableFieldLabelConversionsOfKind(t,
testapi.Default.GroupVersion().String(), testapi.Default.GroupVersion().String(),
"Endpoints", "Endpoints",
labels.Set(fieldsSet), fieldsSet,
nil, nil,
) )
} }

View File

@ -70,7 +70,7 @@ func (eventStrategy) AllowUnconditionalUpdate() bool {
return true 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} return &generic.SelectionPredicate{Label: label, Field: field, GetAttrs: getAttrs}
} }

View File

@ -94,7 +94,7 @@ func TestSelectableFieldLabelConversions(t *testing.T) {
apitesting.TestSelectableFieldLabelConversionsOfKind(t, apitesting.TestSelectableFieldLabelConversionsOfKind(t,
testapi.Default.GroupVersion().String(), testapi.Default.GroupVersion().String(),
"Event", "Event",
labels.Set(fset), fset,
nil, nil,
) )
} }

View File

@ -68,7 +68,11 @@ func (s *SelectionPredicate) Matches(obj runtime.Object) (bool, error) {
if err != nil { if err != nil {
return false, err 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 // 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 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 ( var (
// Assert implementations match the interface. // Assert implementations match the interface.
_ = Matcher(matchKey{})
_ = Matcher(&SelectionPredicate{}) _ = Matcher(&SelectionPredicate{})
_ = Matcher(matcherFunc(nil))
) )

View File

@ -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)
}
}

View File

@ -88,7 +88,7 @@ type Store struct {
TTLFunc func(obj runtime.Object, existing uint64, update bool) (uint64, error) TTLFunc func(obj runtime.Object, existing uint64, update bool) (uint64, error)
// Returns a matcher corresponding to the provided labels and fields. // 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 // DeleteCollectionWorkers is the maximum number of workers in a single
// DeleteCollection call. // 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. // 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() list := e.NewListFunc()
filter := e.createFilter(m) filter := e.createFilter(m)
if name, ok := m.MatchesSingle(); ok { 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. // 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) filter := e.createFilter(m)
if name, ok := m.MatchesSingle(); ok { 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) 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 { filterFunc := func(obj runtime.Object) bool {
matches, err := m.Matches(obj) matches, err := m.Matches(obj)
if err != nil { if err != nil {

View File

@ -83,45 +83,33 @@ func NewTestGenericStoreRegistry(t *testing.T) (*etcdtesting.EtcdTestServer, *St
return newTestGenericStoreRegistry(t, false) 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. // Makes testing simpler.
type setMatcher struct { func matchPodName(names ...string) *generic.SelectionPredicate {
sets.String // 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...))
func (sm setMatcher) Matches(obj runtime.Object) (bool, error) { if err != nil {
pod, ok := obj.(*api.Pod) panic("Labels requirement must validate successfully")
if !ok {
return false, fmt.Errorf("wrong object")
} }
return sm.Has(pod.Name), nil return &generic.SelectionPredicate{
} Label: labels.Everything().Add(*l),
Field: fields.Everything(),
func (sm setMatcher) MatchesSingle() (string, bool) { GetAttrs: func(obj runtime.Object) (label labels.Set, field fields.Set, err error) {
if sm.Len() == 1 { pod := obj.(*api.Pod)
// Since pod name is its key, we can optimize this case. return labels.Set{"name": pod.ObjectMeta.Name}, nil, nil
return sm.List()[0], true },
} }
return "", false
} }
func (sm setMatcher) MatcherIndex() []storage.MatchValue { func matchEverything() *generic.SelectionPredicate {
return nil return &generic.SelectionPredicate{
} Label: labels.Everything(),
Field: fields.Everything(),
// everythingMatcher matches everything GetAttrs: func(obj runtime.Object) (label labels.Set, field fields.Set, err error) {
type everythingMatcher struct{} return nil, nil, nil
},
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 TestStoreList(t *testing.T) { func TestStoreList(t *testing.T) {
@ -139,34 +127,34 @@ func TestStoreList(t *testing.T) {
table := map[string]struct { table := map[string]struct {
in *api.PodList in *api.PodList
m generic.Matcher m *generic.SelectionPredicate
out runtime.Object out runtime.Object
context api.Context context api.Context
}{ }{
"notFound": { "notFound": {
in: nil, in: nil,
m: everythingMatcher{}, m: matchEverything(),
out: &api.PodList{Items: []api.Pod{}}, out: &api.PodList{Items: []api.Pod{}},
}, },
"normal": { "normal": {
in: &api.PodList{Items: []api.Pod{*podA, *podB}}, in: &api.PodList{Items: []api.Pod{*podA, *podB}},
m: everythingMatcher{}, m: matchEverything(),
out: &api.PodList{Items: []api.Pod{*podA, *podB}}, out: &api.PodList{Items: []api.Pod{*podA, *podB}},
}, },
"normalFiltered": { "normalFiltered": {
in: &api.PodList{Items: []api.Pod{*podA, *podB}}, in: &api.PodList{Items: []api.Pod{*podA, *podB}},
m: setMatcher{sets.NewString("foo")}, m: matchPodName("foo"),
out: &api.PodList{Items: []api.Pod{*podB}}, out: &api.PodList{Items: []api.Pod{*podB}},
}, },
"normalFilteredNoNamespace": { "normalFilteredNoNamespace": {
in: &api.PodList{Items: []api.Pod{*podA, *podB}}, in: &api.PodList{Items: []api.Pod{*podA, *podB}},
m: setMatcher{sets.NewString("foo")}, m: matchPodName("foo"),
out: &api.PodList{Items: []api.Pod{*podB}}, out: &api.PodList{Items: []api.Pod{*podB}},
context: noNamespaceContext, context: noNamespaceContext,
}, },
"normalFilteredMatchMultiple": { "normalFilteredMatchMultiple": {
in: &api.PodList{Items: []api.Pod{*podA, *podB}}, 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}}, out: &api.PodList{Items: []api.Pod{*podB}},
}, },
} }
@ -930,7 +918,7 @@ func TestStoreDeleteCollectionWithWatch(t *testing.T) {
} }
podCreated := objCreated.(*api.Pod) 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 { if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
@ -960,18 +948,18 @@ func TestStoreWatch(t *testing.T) {
noNamespaceContext := api.NewContext() noNamespaceContext := api.NewContext()
table := map[string]struct { table := map[string]struct {
generic.Matcher selectPred *generic.SelectionPredicate
context api.Context context api.Context
}{ }{
"single": { "single": {
Matcher: setMatcher{sets.NewString("foo")}, selectPred: matchPodName("foo"),
}, },
"multi": { "multi": {
Matcher: setMatcher{sets.NewString("foo", "bar")}, selectPred: matchPodName("foo", "bar"),
}, },
"singleNoNamespace": { "singleNoNamespace": {
Matcher: setMatcher{sets.NewString("foo")}, selectPred: matchPodName("foo"),
context: noNamespaceContext, context: noNamespaceContext,
}, },
} }
@ -989,7 +977,7 @@ func TestStoreWatch(t *testing.T) {
} }
server, registry := NewTestGenericStoreRegistry(t) server, registry := NewTestGenericStoreRegistry(t)
wi, err := registry.WatchPredicate(ctx, m, "0") wi, err := registry.WatchPredicate(ctx, m.selectPred, "0")
if err != nil { if err != nil {
t.Errorf("%v: unexpected error: %v", name, err) t.Errorf("%v: unexpected error: %v", name, err)
} else { } else {
@ -1048,7 +1036,7 @@ func newTestGenericStoreRegistry(t *testing.T, hasCacheEnabled bool) (*etcdtesti
return path.Join(podPrefix, id), nil return path.Join(podPrefix, id), nil
}, },
ObjectNameFunc: func(obj runtime.Object) (string, error) { return obj.(*api.Pod).Name, 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{ return &generic.SelectionPredicate{
Label: label, Label: label,
Field: field, Field: field,

View File

@ -85,10 +85,10 @@ func (autoscalerStrategy) AllowUnconditionalUpdate() bool {
} }
func AutoscalerToSelectableFields(hpa *autoscaling.HorizontalPodAutoscaler) fields.Set { 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{ return &generic.SelectionPredicate{
Label: label, Label: label,
Field: field, Field: field,

View File

@ -23,14 +23,13 @@ import (
"k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/api/testapi"
apitesting "k8s.io/kubernetes/pkg/api/testing" apitesting "k8s.io/kubernetes/pkg/api/testing"
"k8s.io/kubernetes/pkg/apis/autoscaling" "k8s.io/kubernetes/pkg/apis/autoscaling"
"k8s.io/kubernetes/pkg/labels"
) )
func TestSelectableFieldLabelConversions(t *testing.T) { func TestSelectableFieldLabelConversions(t *testing.T) {
apitesting.TestSelectableFieldLabelConversionsOfKind(t, apitesting.TestSelectableFieldLabelConversionsOfKind(t,
testapi.Autoscaling.GroupVersion().String(), testapi.Autoscaling.GroupVersion().String(),
"Autoscaler", "Autoscaler",
labels.Set(AutoscalerToSelectableFields(&autoscaling.HorizontalPodAutoscaler{})), AutoscalerToSelectableFields(&autoscaling.HorizontalPodAutoscaler{}),
nil, nil,
) )
} }

View File

@ -105,7 +105,7 @@ func IngressToSelectableFields(ingress *extensions.Ingress) fields.Set {
// MatchIngress is the filter used by the generic etcd backend to ingress // 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 // watch events from etcd to clients of the apiserver only interested in specific
// labels/fields. // 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{ return &generic.SelectionPredicate{
Label: label, Label: label,
Field: field, Field: field,

View File

@ -23,7 +23,6 @@ import (
"k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/api/testapi"
apitesting "k8s.io/kubernetes/pkg/api/testing" apitesting "k8s.io/kubernetes/pkg/api/testing"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/util/intstr" "k8s.io/kubernetes/pkg/util/intstr"
) )
@ -136,7 +135,7 @@ func TestSelectableFieldLabelConversions(t *testing.T) {
apitesting.TestSelectableFieldLabelConversionsOfKind(t, apitesting.TestSelectableFieldLabelConversionsOfKind(t,
testapi.Extensions.GroupVersion().String(), testapi.Extensions.GroupVersion().String(),
"Ingress", "Ingress",
labels.Set(IngressToSelectableFields(&extensions.Ingress{})), IngressToSelectableFields(&extensions.Ingress{}),
nil, nil,
) )
} }

View File

@ -166,7 +166,7 @@ func JobToSelectableFields(job *batch.Job) fields.Set {
// MatchJob is the filter used by the generic etcd backend to route // 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 // watch events from etcd to clients of the apiserver only interested in specific
// labels/fields. // 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{ return &generic.SelectionPredicate{
Label: label, Label: label,
Field: field, Field: field,

View File

@ -25,7 +25,6 @@ import (
apitesting "k8s.io/kubernetes/pkg/api/testing" apitesting "k8s.io/kubernetes/pkg/api/testing"
"k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apis/batch" "k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/types" "k8s.io/kubernetes/pkg/types"
) )
@ -226,7 +225,7 @@ func TestSelectableFieldLabelConversions(t *testing.T) {
apitesting.TestSelectableFieldLabelConversionsOfKind(t, apitesting.TestSelectableFieldLabelConversionsOfKind(t,
testapi.Extensions.GroupVersion().String(), testapi.Extensions.GroupVersion().String(),
"Job", "Job",
labels.Set(JobToSelectableFields(&batch.Job{})), JobToSelectableFields(&batch.Job{}),
nil, nil,
) )
} }

View File

@ -75,7 +75,7 @@ func (limitrangeStrategy) AllowUnconditionalUpdate() bool {
} }
func LimitRangeToSelectableFields(limitRange *api.LimitRange) fields.Set { func LimitRangeToSelectableFields(limitRange *api.LimitRange) fields.Set {
return fields.Set{} return nil
} }
func (limitrangeStrategy) Export(api.Context, runtime.Object, bool) error { func (limitrangeStrategy) Export(api.Context, runtime.Object, bool) error {
@ -85,7 +85,7 @@ func (limitrangeStrategy) Export(api.Context, runtime.Object, bool) error {
return nil 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{ return &generic.SelectionPredicate{
Label: label, Label: label,
Field: field, Field: field,

View File

@ -22,14 +22,13 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/api/testapi"
apitesting "k8s.io/kubernetes/pkg/api/testing" apitesting "k8s.io/kubernetes/pkg/api/testing"
"k8s.io/kubernetes/pkg/labels"
) )
func TestSelectableFieldLabelConversions(t *testing.T) { func TestSelectableFieldLabelConversions(t *testing.T) {
apitesting.TestSelectableFieldLabelConversionsOfKind(t, apitesting.TestSelectableFieldLabelConversionsOfKind(t,
testapi.Default.GroupVersion().String(), testapi.Default.GroupVersion().String(),
"LimitRange", "LimitRange",
labels.Set(LimitRangeToSelectableFields(&api.LimitRange{})), LimitRangeToSelectableFields(&api.LimitRange{}),
nil, nil,
) )
} }

View File

@ -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. // MatchNamespace returns a generic matcher for a given label and field selector.
func MatchNamespace(label labels.Selector, field fields.Selector) generic.Matcher { func MatchNamespace(label labels.Selector, field fields.Selector) *generic.SelectionPredicate {
return generic.MatcherFunc(func(obj runtime.Object) (bool, error) { return &generic.SelectionPredicate{
namespaceObj, ok := obj.(*api.Namespace) Label: label,
if !ok { Field: field,
return false, fmt.Errorf("not a namespace") GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) {
} namespaceObj, ok := obj.(*api.Namespace)
fields := NamespaceToSelectableFields(namespaceObj) if !ok {
return label.Matches(labels.Set(namespaceObj.Labels)) && field.Matches(fields), nil 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 // NamespaceToSelectableFields returns a field set that represents the object
func NamespaceToSelectableFields(namespace *api.Namespace) labels.Set { func NamespaceToSelectableFields(namespace *api.Namespace) fields.Set {
objectMetaFieldsSet := generic.ObjectMetaFieldsSet(namespace.ObjectMeta, false) objectMetaFieldsSet := generic.ObjectMetaFieldsSet(namespace.ObjectMeta, false)
specificFieldsSet := fields.Set{ specificFieldsSet := fields.Set{
"status.phase": string(namespace.Status.Phase), "status.phase": string(namespace.Status.Phase),
// This is a bug, but we need to support it for backward compatibility. // This is a bug, but we need to support it for backward compatibility.
"name": namespace.Name, "name": namespace.Name,
} }
return labels.Set(generic.MergeFieldsSets(objectMetaFieldsSet, specificFieldsSet)) return generic.MergeFieldsSets(objectMetaFieldsSet, specificFieldsSet)
} }

View File

@ -97,7 +97,7 @@ func NetworkPolicyToSelectableFields(networkPolicy *extensions.NetworkPolicy) fi
// MatchNetworkPolicy is the filter used by the generic etcd backend to watch events // 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. // 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{ return &generic.SelectionPredicate{
Label: label, Label: label,
Field: field, Field: field,

View File

@ -147,7 +147,7 @@ func NodeToSelectableFields(node *api.Node) fields.Set {
} }
// MatchNode returns a generic matcher for a given label and field selector. // 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{ return &generic.SelectionPredicate{
Label: label, Label: label,
Field: field, Field: field,

View File

@ -51,7 +51,7 @@ func TestSelectableFieldLabelConversions(t *testing.T) {
apitesting.TestSelectableFieldLabelConversionsOfKind(t, apitesting.TestSelectableFieldLabelConversionsOfKind(t,
testapi.Default.GroupVersion().String(), testapi.Default.GroupVersion().String(),
"Node", "Node",
labels.Set(NodeToSelectableFields(&api.Node{})), NodeToSelectableFields(&api.Node{}),
nil, nil,
) )
} }

View File

@ -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. // MatchPersistentVolume returns a generic matcher for a given label and field selector.
func MatchPersistentVolumes(label labels.Selector, field fields.Selector) generic.Matcher { func MatchPersistentVolumes(label labels.Selector, field fields.Selector) *generic.SelectionPredicate {
return generic.MatcherFunc(func(obj runtime.Object) (bool, error) { return &generic.SelectionPredicate{
persistentvolumeObj, ok := obj.(*api.PersistentVolume) Label: label,
if !ok { Field: field,
return false, fmt.Errorf("not a persistentvolume") GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) {
} persistentvolumeObj, ok := obj.(*api.PersistentVolume)
fields := PersistentVolumeToSelectableFields(persistentvolumeObj) if !ok {
return label.Matches(labels.Set(persistentvolumeObj.Labels)) && field.Matches(fields), nil 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 // PersistentVolumeToSelectableFields returns a field set that represents the object
func PersistentVolumeToSelectableFields(persistentvolume *api.PersistentVolume) labels.Set { func PersistentVolumeToSelectableFields(persistentvolume *api.PersistentVolume) fields.Set {
objectMetaFieldsSet := generic.ObjectMetaFieldsSet(persistentvolume.ObjectMeta, false) objectMetaFieldsSet := generic.ObjectMetaFieldsSet(persistentvolume.ObjectMeta, false)
specificFieldsSet := fields.Set{ specificFieldsSet := fields.Set{
// This is a bug, but we need to support it for backward compatibility. // This is a bug, but we need to support it for backward compatibility.
"name": persistentvolume.Name, "name": persistentvolume.Name,
} }
return labels.Set(generic.MergeFieldsSets(objectMetaFieldsSet, specificFieldsSet)) return generic.MergeFieldsSets(objectMetaFieldsSet, specificFieldsSet)
} }

View File

@ -95,23 +95,26 @@ func (persistentvolumeclaimStatusStrategy) ValidateUpdate(ctx api.Context, obj,
} }
// MatchPersistentVolumeClaim returns a generic matcher for a given label and field selector. // MatchPersistentVolumeClaim returns a generic matcher for a given label and field selector.
func MatchPersistentVolumeClaim(label labels.Selector, field fields.Selector) generic.Matcher { func MatchPersistentVolumeClaim(label labels.Selector, field fields.Selector) *generic.SelectionPredicate {
return generic.MatcherFunc(func(obj runtime.Object) (bool, error) { return &generic.SelectionPredicate{
persistentvolumeclaimObj, ok := obj.(*api.PersistentVolumeClaim) Label: label,
if !ok { Field: field,
return false, fmt.Errorf("not a persistentvolumeclaim") GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) {
} persistentvolumeclaimObj, ok := obj.(*api.PersistentVolumeClaim)
fields := PersistentVolumeClaimToSelectableFields(persistentvolumeclaimObj) if !ok {
return label.Matches(labels.Set(persistentvolumeclaimObj.Labels)) && field.Matches(fields), nil 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 // PersistentVolumeClaimToSelectableFields returns a field set that represents the object
func PersistentVolumeClaimToSelectableFields(persistentvolumeclaim *api.PersistentVolumeClaim) labels.Set { func PersistentVolumeClaimToSelectableFields(persistentvolumeclaim *api.PersistentVolumeClaim) fields.Set {
objectMetaFieldsSet := generic.ObjectMetaFieldsSet(persistentvolumeclaim.ObjectMeta, true) objectMetaFieldsSet := generic.ObjectMetaFieldsSet(persistentvolumeclaim.ObjectMeta, true)
specificFieldsSet := fields.Set{ specificFieldsSet := fields.Set{
// This is a bug, but we need to support it for backward compatibility. // This is a bug, but we need to support it for backward compatibility.
"name": persistentvolumeclaim.Name, "name": persistentvolumeclaim.Name,
} }
return labels.Set(generic.MergeFieldsSets(objectMetaFieldsSet, specificFieldsSet)) return generic.MergeFieldsSets(objectMetaFieldsSet, specificFieldsSet)
} }

View File

@ -103,7 +103,7 @@ func PetSetToSelectableFields(petSet *apps.PetSet) fields.Set {
// MatchPetSet is the filter used by the generic etcd backend to watch events // 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. // 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{ return &generic.SelectionPredicate{
Label: label, Label: label,
Field: field, Field: field,

View File

@ -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. // 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{ return &generic.SelectionPredicate{
Label: label, Label: label,
Field: field, Field: field,

View File

@ -252,7 +252,7 @@ func TestSelectableFieldLabelConversions(t *testing.T) {
apitesting.TestSelectableFieldLabelConversionsOfKind(t, apitesting.TestSelectableFieldLabelConversionsOfKind(t,
testapi.Default.GroupVersion().String(), testapi.Default.GroupVersion().String(),
"Pod", "Pod",
labels.Set(PodToSelectableFields(&api.Pod{})), PodToSelectableFields(&api.Pod{}),
nil, nil,
) )
} }

View File

@ -102,7 +102,7 @@ func PodDisruptionBudgetToSelectableFields(podDisruptionBudget *policy.PodDisrup
// MatchPodDisruptionBudget is the filter used by the generic etcd backend to watch events // 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. // 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{ return &generic.SelectionPredicate{
Label: label, Label: label,
Field: field, Field: field,

View File

@ -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. // 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{ return &generic.SelectionPredicate{
Label: label, Label: label,
Field: field, Field: field,

View File

@ -83,10 +83,10 @@ func (podTemplateStrategy) Export(ctx api.Context, obj runtime.Object, exact boo
} }
func PodTemplateToSelectableFields(podTemplate *api.PodTemplate) fields.Set { 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{ return &generic.SelectionPredicate{
Label: label, Label: label,
Field: field, Field: field,

View File

@ -22,14 +22,13 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/api/testapi"
apitesting "k8s.io/kubernetes/pkg/api/testing" apitesting "k8s.io/kubernetes/pkg/api/testing"
"k8s.io/kubernetes/pkg/labels"
) )
func TestSelectableFieldLabelConversions(t *testing.T) { func TestSelectableFieldLabelConversions(t *testing.T) {
apitesting.TestSelectableFieldLabelConversionsOfKind(t, apitesting.TestSelectableFieldLabelConversionsOfKind(t,
testapi.Default.GroupVersion().String(), testapi.Default.GroupVersion().String(),
"PodTemplate", "PodTemplate",
labels.Set(PodTemplateToSelectableFields(&api.PodTemplate{})), PodTemplateToSelectableFields(&api.PodTemplate{}),
nil, nil,
) )
} }

View File

@ -114,7 +114,7 @@ func ReplicaSetToSelectableFields(rs *extensions.ReplicaSet) fields.Set {
// MatchReplicaSet is the filter used by the generic etcd backend to route // 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 // watch events from etcd to clients of the apiserver only interested in specific
// labels/fields. // 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{ return &generic.SelectionPredicate{
Label: label, Label: label,
Field: field, Field: field,

View File

@ -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. // MatchResourceQuota returns a generic matcher for a given label and field selector.
func MatchResourceQuota(label labels.Selector, field fields.Selector) generic.Matcher { func MatchResourceQuota(label labels.Selector, field fields.Selector) *generic.SelectionPredicate {
return generic.MatcherFunc(func(obj runtime.Object) (bool, error) { return &generic.SelectionPredicate{
resourcequotaObj, ok := obj.(*api.ResourceQuota) Label: label,
if !ok { Field: field,
return false, fmt.Errorf("not a resourcequota") GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) {
} resourcequotaObj, ok := obj.(*api.ResourceQuota)
fields := ResourceQuotaToSelectableFields(resourcequotaObj) if !ok {
return label.Matches(labels.Set(resourcequotaObj.Labels)) && field.Matches(fields), nil 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 // ResourceQuotaToSelectableFields returns a field set that represents the object
func ResourceQuotaToSelectableFields(resourcequota *api.ResourceQuota) labels.Set { func ResourceQuotaToSelectableFields(resourcequota *api.ResourceQuota) fields.Set {
return labels.Set(generic.ObjectMetaFieldsSet(resourcequota.ObjectMeta, true)) return generic.ObjectMetaFieldsSet(resourcequota.ObjectMeta, true)
} }

View File

@ -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. // Matcher returns a generic matcher for a given label and field selector.
func Matcher(label labels.Selector, field fields.Selector) generic.Matcher { func Matcher(label labels.Selector, field fields.Selector) *generic.SelectionPredicate {
return generic.MatcherFunc(func(obj runtime.Object) (bool, error) { return &generic.SelectionPredicate{
sa, ok := obj.(*rbac.Role) Label: label,
if !ok { Field: field,
return false, fmt.Errorf("not a Role") GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) {
} role, ok := obj.(*rbac.Role)
fields := SelectableFields(sa) if !ok {
return label.Matches(labels.Set(sa.Labels)) && field.Matches(fields), nil 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 // SelectableFields returns a field set that can be used for filter selection
func SelectableFields(obj *rbac.Role) labels.Set { func SelectableFields(obj *rbac.Role) fields.Set {
return labels.Set{} return nil
} }

View File

@ -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. // Matcher returns a generic matcher for a given label and field selector.
func Matcher(label labels.Selector, field fields.Selector) generic.Matcher { func Matcher(label labels.Selector, field fields.Selector) *generic.SelectionPredicate {
return generic.MatcherFunc(func(obj runtime.Object) (bool, error) { return &generic.SelectionPredicate{
sa, ok := obj.(*rbac.RoleBinding) Label: label,
if !ok { Field: field,
return false, fmt.Errorf("not a RoleBinding") GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) {
} roleBinding, ok := obj.(*rbac.RoleBinding)
fields := SelectableFields(sa) if !ok {
return label.Matches(labels.Set(sa.Labels)) && field.Matches(fields), nil 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 // SelectableFields returns a field set that can be used for filter selection
func SelectableFields(obj *rbac.RoleBinding) labels.Set { func SelectableFields(obj *rbac.RoleBinding) fields.Set {
return labels.Set{} return nil
} }

View File

@ -104,7 +104,7 @@ func ScheduledJobToSelectableFields(scheduledJob *batch.ScheduledJob) fields.Set
// MatchScheduledJob is the filter used by the generic etcd backend to route // 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 // watch events from etcd to clients of the apiserver only interested in specific
// labels/fields. // 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{ return &generic.SelectionPredicate{
Label: label, Label: label,
Field: field, Field: field,

View File

@ -23,7 +23,6 @@ import (
apitesting "k8s.io/kubernetes/pkg/api/testing" apitesting "k8s.io/kubernetes/pkg/api/testing"
"k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apis/batch" "k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/labels"
) )
func newBool(a bool) *bool { func newBool(a bool) *bool {
@ -168,7 +167,7 @@ func TestSelectableFieldLabelConversions(t *testing.T) {
apitesting.TestSelectableFieldLabelConversionsOfKind(t, apitesting.TestSelectableFieldLabelConversionsOfKind(t,
"batch/v2alpha1", "batch/v2alpha1",
"ScheduledJob", "ScheduledJob",
labels.Set(ScheduledJobToSelectableFields(&batch.ScheduledJob{})), ScheduledJobToSelectableFields(&batch.ScheduledJob{}),
nil, nil,
) )
} }

View File

@ -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. // Matcher returns a generic matcher for a given label and field selector.
func Matcher(label labels.Selector, field fields.Selector) generic.Matcher { func Matcher(label labels.Selector, field fields.Selector) *generic.SelectionPredicate {
return generic.MatcherFunc(func(obj runtime.Object) (bool, error) { return &generic.SelectionPredicate{
sa, ok := obj.(*api.Secret) Label: label,
if !ok { Field: field,
return false, fmt.Errorf("not a secret") GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) {
} secret, ok := obj.(*api.Secret)
fields := SelectableFields(sa) if !ok {
return label.Matches(labels.Set(sa.Labels)) && field.Matches(fields), nil 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 // SelectableFields returns a field set that can be used for filter selection
func SelectableFields(obj *api.Secret) labels.Set { func SelectableFields(obj *api.Secret) fields.Set {
objectMetaFieldsSet := generic.ObjectMetaFieldsSet(obj.ObjectMeta, true) objectMetaFieldsSet := generic.ObjectMetaFieldsSet(obj.ObjectMeta, true)
secretSpecificFieldsSet := fields.Set{ secretSpecificFieldsSet := fields.Set{
"type": string(obj.Type), "type": string(obj.Type),
} }
return labels.Set(generic.MergeFieldsSets(objectMetaFieldsSet, secretSpecificFieldsSet)) return generic.MergeFieldsSets(objectMetaFieldsSet, secretSpecificFieldsSet)
} }

View File

@ -100,7 +100,7 @@ func (svcStrategy) Export(ctx api.Context, obj runtime.Object, exact bool) error
return nil 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{ return &generic.SelectionPredicate{
Label: label, Label: label,
Field: field, Field: field,

View File

@ -25,7 +25,6 @@ import (
"k8s.io/kubernetes/pkg/api/rest" "k8s.io/kubernetes/pkg/api/rest"
"k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/api/testapi"
apitesting "k8s.io/kubernetes/pkg/api/testing" apitesting "k8s.io/kubernetes/pkg/api/testing"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/intstr" "k8s.io/kubernetes/pkg/util/intstr"
) )
@ -216,7 +215,7 @@ func TestSelectableFieldLabelConversions(t *testing.T) {
apitesting.TestSelectableFieldLabelConversionsOfKind(t, apitesting.TestSelectableFieldLabelConversionsOfKind(t,
testapi.Default.GroupVersion().String(), testapi.Default.GroupVersion().String(),
"Service", "Service",
labels.Set(ServiceToSelectableFields(&api.Service{})), ServiceToSelectableFields(&api.Service{}),
nil, nil,
) )
} }

View File

@ -77,18 +77,21 @@ func (strategy) AllowUnconditionalUpdate() bool {
} }
// Matcher returns a generic matcher for a given label and field selector. // Matcher returns a generic matcher for a given label and field selector.
func Matcher(label labels.Selector, field fields.Selector) generic.Matcher { func Matcher(label labels.Selector, field fields.Selector) *generic.SelectionPredicate {
return generic.MatcherFunc(func(obj runtime.Object) (bool, error) { return &generic.SelectionPredicate{
sa, ok := obj.(*api.ServiceAccount) Label: label,
if !ok { Field: field,
return false, fmt.Errorf("not a serviceaccount") GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) {
} sa, ok := obj.(*api.ServiceAccount)
fields := SelectableFields(sa) if !ok {
return label.Matches(labels.Set(sa.Labels)) && field.Matches(fields), nil 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 // SelectableFields returns a field set that represents the object
func SelectableFields(obj *api.ServiceAccount) labels.Set { func SelectableFields(obj *api.ServiceAccount) fields.Set {
return labels.Set(generic.ObjectMetaFieldsSet(obj.ObjectMeta, true)) return generic.ObjectMetaFieldsSet(obj.ObjectMeta, true)
} }

View File

@ -77,7 +77,7 @@ func (storageClassStrategy) AllowUnconditionalUpdate() bool {
} }
// MatchStorageClass returns a generic matcher for a given label and field selector. // 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{ return &generic.SelectionPredicate{
Label: label, Label: label,
Field: field, Field: field,

View File

@ -78,18 +78,21 @@ func (strategy) AllowUnconditionalUpdate() bool {
} }
// Matcher returns a generic matcher for a given label and field selector. // Matcher returns a generic matcher for a given label and field selector.
func Matcher(label labels.Selector, field fields.Selector) generic.Matcher { func Matcher(label labels.Selector, field fields.Selector) *generic.SelectionPredicate {
return generic.MatcherFunc(func(obj runtime.Object) (bool, error) { return &generic.SelectionPredicate{
sa, ok := obj.(*extensions.ThirdPartyResource) Label: label,
if !ok { Field: field,
return false, fmt.Errorf("not a ThirdPartyResource") GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) {
} tpr, ok := obj.(*extensions.ThirdPartyResource)
fields := SelectableFields(sa) if !ok {
return label.Matches(labels.Set(sa.Labels)) && field.Matches(fields), nil 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 // SelectableFields returns a field set that can be used for filter selection
func SelectableFields(obj *extensions.ThirdPartyResource) labels.Set { func SelectableFields(obj *extensions.ThirdPartyResource) fields.Set {
return labels.Set{} return nil
} }

View File

@ -75,18 +75,21 @@ func (strategy) AllowUnconditionalUpdate() bool {
} }
// Matcher returns a generic matcher for a given label and field selector. // Matcher returns a generic matcher for a given label and field selector.
func Matcher(label labels.Selector, field fields.Selector) generic.Matcher { func Matcher(label labels.Selector, field fields.Selector) *generic.SelectionPredicate {
return generic.MatcherFunc(func(obj runtime.Object) (bool, error) { return &generic.SelectionPredicate{
sa, ok := obj.(*extensions.ThirdPartyResourceData) Label: label,
if !ok { Field: field,
return false, fmt.Errorf("not a ThirdPartyResourceData") GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) {
} tprd, ok := obj.(*extensions.ThirdPartyResourceData)
fields := SelectableFields(sa) if !ok {
return label.Matches(labels.Set(sa.Labels)) && field.Matches(fields), nil 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 // SelectableFields returns a field set that can be used for filter selection
func SelectableFields(obj *extensions.ThirdPartyResourceData) labels.Set { func SelectableFields(obj *extensions.ThirdPartyResourceData) fields.Set {
return labels.Set{} return nil
} }