Single-key matching behavior in generic.Matcher

This commit is contained in:
Daniel Smith
2015-04-02 11:11:00 -07:00
parent 3d1dfd47ee
commit 0c2d3ffe68
9 changed files with 243 additions and 141 deletions

View File

@@ -23,9 +23,6 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic"
etcdgeneric "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic/etcd"
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/minion"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
@@ -49,14 +46,11 @@ func NewStorage(h tools.EtcdHelper, connection client.ConnectionInfoGetter) *RES
KeyFunc: func(ctx api.Context, name string) (string, error) {
return prefix + "/" + name, nil
},
WatchSingleFieldName: "name",
ObjectNameFunc: func(obj runtime.Object) (string, error) {
return obj.(*api.Node).Name, nil
},
PredicateFunc: func(label labels.Selector, field fields.Selector) generic.Matcher {
return minion.MatchNode(label, field)
},
EndpointName: "minion",
PredicateFunc: minion.MatchNode,
EndpointName: "minion",
CreateStrategy: minion.Strategy,
UpdateStrategy: minion.Strategy,

View File

@@ -347,59 +347,6 @@ func TestEtcdWatchNodesMatch(t *testing.T) {
watching.Stop()
}
func TestEtcdWatchNodesFields(t *testing.T) {
ctx := api.NewDefaultContext()
storage, fakeClient := newStorage(t)
node := validNewNode()
nodeBytes, _ := latest.Codec.Encode(node)
testFieldMap := map[int][]fields.Set{
PASS: {
{"name": "foo"},
},
FAIL: {
{"name": "bar"},
},
}
for _, singleWatchField := range []string{"", "name"} {
storage.WatchSingleFieldName = singleWatchField
for expectedResult, fieldSet := range testFieldMap {
for _, field := range fieldSet {
watching, err := storage.Watch(ctx,
labels.Everything(),
field.AsSelector(),
"1",
)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
fakeClient.WaitForWatchCompletion()
fakeClient.WatchResponse <- &etcd.Response{
Action: "create",
Node: &etcd.Node{
Value: string(nodeBytes),
},
}
select {
case r, ok := <-watching.ResultChan():
if expectedResult == FAIL {
t.Errorf("unexpected result from channel %#v", r)
}
if !ok {
t.Errorf("watching channel should be open")
}
case <-time.After(time.Millisecond * 100):
if expectedResult == PASS {
t.Errorf("unexpected timeout from result channel")
}
}
watching.Stop()
}
}
}
}
func TestEtcdWatchNodesNotMatch(t *testing.T) {
ctx := api.NewDefaultContext()
storage, fakeClient := newStorage(t)

View File

@@ -83,22 +83,25 @@ type ResourceGetter interface {
}
// NodeToSelectableFields returns a label set that represents the object.
func NodeToSelectableFields(node *api.Node) labels.Set {
return labels.Set{
func NodeToSelectableFields(node *api.Node) fields.Set {
return fields.Set{
"name": node.Name,
}
}
// MatchNode returns a generic matcher for a given label and field selector.
func MatchNode(label labels.Selector, field fields.Selector) generic.Matcher {
return generic.MatcherFunc(func(obj runtime.Object) (bool, error) {
nodeObj, ok := obj.(*api.Node)
if !ok {
return false, fmt.Errorf("not a node")
}
fields := NodeToSelectableFields(nodeObj)
return label.Matches(labels.Set(nodeObj.Labels)) && field.Matches(fields), nil
})
return &generic.SelectionPredicate{
Label: label,
Field: field,
GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) {
nodeObj, ok := obj.(*api.Node)
if !ok {
return nil, nil, fmt.Errorf("not a node")
}
return labels.Set(nodeObj.ObjectMeta.Labels), NodeToSelectableFields(nodeObj), nil
},
}
}
// ResourceLocation returns a URL to which one can send traffic for the specified node.

View File

@@ -0,0 +1,45 @@
/*
Copyright 2015 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package minion
import (
"testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
)
func TestMatchNode(t *testing.T) {
testFieldMap := map[bool][]fields.Set{
true: {
{"name": "foo"},
},
false: {
{"foo": "bar"},
},
}
for expectedResult, fieldSet := range testFieldMap {
for _, field := range fieldSet {
m := MatchNode(labels.Everything(), field.AsSelector())
_, matchesSingle := m.MatchesSingle()
if e, a := expectedResult, matchesSingle; e != a {
t.Errorf("%+v: expected %v, got %v", e, a)
}
}
}
}