Merge pull request #18157 from sdminonne/LabelSelector_internalSelector

renaming labels.LabelSelector to labels.internalSelector
This commit is contained in:
David Oppenheimer 2015-12-13 20:03:49 -08:00
commit 725a84ffe0
3 changed files with 92 additions and 82 deletions

View File

@ -18,7 +18,6 @@ package extensions
import ( import (
"fmt" "fmt"
"sort"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
@ -34,13 +33,13 @@ func LabelSelectorAsSelector(ps *LabelSelector) (labels.Selector, error) {
if len(ps.MatchLabels)+len(ps.MatchExpressions) == 0 { if len(ps.MatchLabels)+len(ps.MatchExpressions) == 0 {
return labels.Everything(), nil return labels.Everything(), nil
} }
selector := labels.LabelSelector{} selector := labels.NewSelector()
for k, v := range ps.MatchLabels { for k, v := range ps.MatchLabels {
req, err := labels.NewRequirement(k, labels.InOperator, sets.NewString(v)) r, err := labels.NewRequirement(k, labels.InOperator, sets.NewString(v))
if err != nil { if err != nil {
return nil, err return nil, err
} }
selector = append(selector, *req) selector = selector.Add(*r)
} }
for _, expr := range ps.MatchExpressions { for _, expr := range ps.MatchExpressions {
var op labels.Operator var op labels.Operator
@ -56,13 +55,12 @@ func LabelSelectorAsSelector(ps *LabelSelector) (labels.Selector, error) {
default: default:
return nil, fmt.Errorf("%q is not a valid pod selector operator", expr.Operator) return nil, fmt.Errorf("%q is not a valid pod selector operator", expr.Operator)
} }
req, err := labels.NewRequirement(expr.Key, op, sets.NewString(expr.Values...)) r, err := labels.NewRequirement(expr.Key, op, sets.NewString(expr.Values...))
if err != nil { if err != nil {
return nil, err return nil, err
} }
selector = append(selector, *req) selector = selector.Add(*r)
} }
sort.Sort(labels.ByKey(selector))
return selector, nil return selector, nil
} }

View File

@ -37,21 +37,21 @@ type Selector interface {
// String returns a human readable string that represents this selector. // String returns a human readable string that represents this selector.
String() string String() string
// Add add a specific requirement for the selector // Add adds requirements to the Selector
Add(key string, operator Operator, values []string) Selector Add(r ...Requirement) Selector
} }
// Everything returns a selector that matches all labels. // Everything returns a selector that matches all labels.
func Everything() Selector { func Everything() Selector {
return LabelSelector{} return internalSelector{}
} }
type nothingSelector struct{} type nothingSelector struct{}
func (n nothingSelector) Matches(_ Labels) bool { return false } func (n nothingSelector) Matches(_ Labels) bool { return false }
func (n nothingSelector) Empty() bool { return false } func (n nothingSelector) Empty() bool { return false }
func (n nothingSelector) String() string { return "<null>" } func (n nothingSelector) String() string { return "<null>" }
func (n nothingSelector) Add(_ string, _ Operator, _ []string) Selector { return n } func (n nothingSelector) Add(_ ...Requirement) Selector { return n }
// Nothing returns a selector that matches no labels // Nothing returns a selector that matches no labels
func Nothing() Selector { func Nothing() Selector {
@ -72,10 +72,13 @@ const (
ExistsOperator Operator = "exists" ExistsOperator Operator = "exists"
) )
//LabelSelector is a list of Requirements. func NewSelector() Selector {
type LabelSelector []Requirement return internalSelector(nil)
}
// Sort by obtain determisitic parser type internalSelector []Requirement
// Sort by key to obtain determisitic parser
type ByKey []Requirement type ByKey []Requirement
func (a ByKey) Len() int { return len(a) } func (a ByKey) Len() int { return len(a) }
@ -178,8 +181,8 @@ func (r *Requirement) Values() sets.String {
return ret return ret
} }
// Return true if the LabelSelector doesn't restrict selection space // Return true if the internalSelector doesn't restrict selection space
func (lsel LabelSelector) Empty() bool { func (lsel internalSelector) Empty() bool {
if lsel == nil { if lsel == nil {
return true return true
} }
@ -228,22 +231,23 @@ func (r *Requirement) String() string {
return buffer.String() return buffer.String()
} }
// Add adds a requirement to the selector. It copies the current selector returning a new one // Add adds requirements to the selector. It copies the current selector returning a new one
func (lsel LabelSelector) Add(key string, operator Operator, values []string) Selector { func (lsel internalSelector) Add(reqs ...Requirement) Selector {
var reqs []Requirement var sel internalSelector
for _, item := range lsel { for _, item := range lsel {
reqs = append(reqs, item) sel = append(sel, item)
} }
if r, err := NewRequirement(key, operator, sets.NewString(values...)); err == nil { for _, r := range reqs {
reqs = append(reqs, *r) sel = append(sel, r)
} }
return LabelSelector(reqs) sort.Sort(ByKey(sel))
return sel
} }
// Matches for a LabelSelector returns true if all // Matches for a internalSelector returns true if all
// its Requirements match the input Labels. If any // its Requirements match the input Labels. If any
// Requirement does not match, false is returned. // Requirement does not match, false is returned.
func (lsel LabelSelector) Matches(l Labels) bool { func (lsel internalSelector) Matches(l Labels) bool {
for _, req := range lsel { for _, req := range lsel {
if matches := req.Matches(l); !matches { if matches := req.Matches(l); !matches {
return false return false
@ -253,8 +257,8 @@ func (lsel LabelSelector) Matches(l Labels) bool {
} }
// String returns a comma-separated string of all // String returns a comma-separated string of all
// the LabelSelector Requirements' human-readable strings. // the internalSelector Requirements' human-readable strings.
func (lsel LabelSelector) String() string { func (lsel internalSelector) String() string {
var reqs []string var reqs []string
for _, req := range lsel { for _, req := range lsel {
reqs = append(reqs, req.String()) reqs = append(reqs, req.String())
@ -473,10 +477,10 @@ func (p *Parser) scan() {
// parse runs the left recursive descending algorithm // parse runs the left recursive descending algorithm
// on input string. It returns a list of Requirement objects. // on input string. It returns a list of Requirement objects.
func (p *Parser) parse() ([]Requirement, error) { func (p *Parser) parse() (internalSelector, error) {
p.scan() // init scannedItems p.scan() // init scannedItems
var requirements []Requirement var requirements internalSelector
for { for {
tok, lit := p.lookahead(Values) tok, lit := p.lookahead(Values)
switch tok { switch tok {
@ -692,7 +696,7 @@ func Parse(selector string) (Selector, error) {
items, error := p.parse() items, error := p.parse()
if error == nil { if error == nil {
sort.Sort(ByKey(items)) // sort to grant determistic parsing sort.Sort(ByKey(items)) // sort to grant determistic parsing
return LabelSelector(items), error return internalSelector(items), error
} }
return nil, error return nil, error
} }
@ -718,18 +722,18 @@ func validateLabelValue(v string) error {
// nil and empty Sets are considered equivalent to Everything(). // nil and empty Sets are considered equivalent to Everything().
func SelectorFromSet(ls Set) Selector { func SelectorFromSet(ls Set) Selector {
if ls == nil { if ls == nil {
return LabelSelector{} return internalSelector{}
} }
var requirements []Requirement var requirements internalSelector
for label, value := range ls { for label, value := range ls {
if r, err := NewRequirement(label, EqualsOperator, sets.NewString(value)); err != nil { if r, err := NewRequirement(label, EqualsOperator, sets.NewString(value)); err != nil {
//TODO: double check errors when input comes from serialization? //TODO: double check errors when input comes from serialization?
return LabelSelector{} return internalSelector{}
} else { } else {
requirements = append(requirements, *r) requirements = append(requirements, *r)
} }
} }
// sort to have deterministic string representation // sort to have deterministic string representation
sort.Sort(ByKey(requirements)) sort.Sort(ByKey(requirements))
return LabelSelector(requirements) return internalSelector(requirements)
} }

View File

@ -168,8 +168,8 @@ func TestSetIsEmpty(t *testing.T) {
if !(Set{}).AsSelector().Empty() { if !(Set{}).AsSelector().Empty() {
t.Errorf("Empty set should be empty") t.Errorf("Empty set should be empty")
} }
if !(LabelSelector(nil)).Empty() { if !(NewSelector()).Empty() {
t.Errorf("Nil LabelSelector should be empty") t.Errorf("Nil Selector should be empty")
} }
} }
@ -313,30 +313,31 @@ func TestRequirementConstructor(t *testing.T) {
func TestToString(t *testing.T) { func TestToString(t *testing.T) {
var req Requirement var req Requirement
toStringTests := []struct { toStringTests := []struct {
In *LabelSelector In *internalSelector
Out string Out string
Valid bool Valid bool
}{ }{
{&LabelSelector{
{&internalSelector{
getRequirement("x", InOperator, sets.NewString("abc", "def"), t), getRequirement("x", InOperator, sets.NewString("abc", "def"), t),
getRequirement("y", NotInOperator, sets.NewString("jkl"), t), getRequirement("y", NotInOperator, sets.NewString("jkl"), t),
getRequirement("z", ExistsOperator, nil, t)}, getRequirement("z", ExistsOperator, nil, t)},
"x in (abc,def),y notin (jkl),z", true}, "x in (abc,def),y notin (jkl),z", true},
{&LabelSelector{ {&internalSelector{
getRequirement("x", NotInOperator, sets.NewString("abc", "def"), t), getRequirement("x", NotInOperator, sets.NewString("abc", "def"), t),
getRequirement("y", NotEqualsOperator, sets.NewString("jkl"), t), getRequirement("y", NotEqualsOperator, sets.NewString("jkl"), t),
getRequirement("z", DoesNotExistOperator, nil, t)}, getRequirement("z", DoesNotExistOperator, nil, t)},
"x notin (abc,def),y!=jkl,!z", true}, "x notin (abc,def),y!=jkl,!z", true},
{&LabelSelector{ {&internalSelector{
getRequirement("x", InOperator, sets.NewString("abc", "def"), t), getRequirement("x", InOperator, sets.NewString("abc", "def"), t),
req}, // adding empty req for the trailing ',' req}, // adding empty req for the trailing ','
"x in (abc,def),", false}, "x in (abc,def),", false},
{&LabelSelector{ {&internalSelector{
getRequirement("x", NotInOperator, sets.NewString("abc"), t), getRequirement("x", NotInOperator, sets.NewString("abc"), t),
getRequirement("y", InOperator, sets.NewString("jkl", "mno"), t), getRequirement("y", InOperator, sets.NewString("jkl", "mno"), t),
getRequirement("z", NotInOperator, sets.NewString(""), t)}, getRequirement("z", NotInOperator, sets.NewString(""), t)},
"x notin (abc),y in (jkl,mno),z notin ()", true}, "x notin (abc),y in (jkl,mno),z notin ()", true},
{&LabelSelector{ {&internalSelector{
getRequirement("x", EqualsOperator, sets.NewString("abc"), t), getRequirement("x", EqualsOperator, sets.NewString("abc"), t),
getRequirement("y", DoubleEqualsOperator, sets.NewString("jkl"), t), getRequirement("y", DoubleEqualsOperator, sets.NewString("jkl"), t),
getRequirement("z", NotEqualsOperator, sets.NewString("a"), t), getRequirement("z", NotEqualsOperator, sets.NewString("a"), t),
@ -352,37 +353,37 @@ func TestToString(t *testing.T) {
} }
} }
func TestRequirementLabelSelectorMatching(t *testing.T) { func TestRequirementSelectorMatching(t *testing.T) {
var req Requirement var req Requirement
labelSelectorMatchingTests := []struct { labelSelectorMatchingTests := []struct {
Set Set Set Set
Sel *LabelSelector Sel Selector
Match bool Match bool
}{ }{
{Set{"x": "foo", "y": "baz"}, &LabelSelector{ {Set{"x": "foo", "y": "baz"}, &internalSelector{
req, req,
}, false}, }, false},
{Set{"x": "foo", "y": "baz"}, &LabelSelector{ {Set{"x": "foo", "y": "baz"}, &internalSelector{
getRequirement("x", InOperator, sets.NewString("foo"), t), getRequirement("x", InOperator, sets.NewString("foo"), t),
getRequirement("y", NotInOperator, sets.NewString("alpha"), t), getRequirement("y", NotInOperator, sets.NewString("alpha"), t),
}, true}, }, true},
{Set{"x": "foo", "y": "baz"}, &LabelSelector{ {Set{"x": "foo", "y": "baz"}, &internalSelector{
getRequirement("x", InOperator, sets.NewString("foo"), t), getRequirement("x", InOperator, sets.NewString("foo"), t),
getRequirement("y", InOperator, sets.NewString("alpha"), t), getRequirement("y", InOperator, sets.NewString("alpha"), t),
}, false}, }, false},
{Set{"y": ""}, &LabelSelector{ {Set{"y": ""}, &internalSelector{
getRequirement("x", NotInOperator, sets.NewString(""), t), getRequirement("x", NotInOperator, sets.NewString(""), t),
getRequirement("y", ExistsOperator, nil, t), getRequirement("y", ExistsOperator, nil, t),
}, true}, }, true},
{Set{"y": ""}, &LabelSelector{ {Set{"y": ""}, &internalSelector{
getRequirement("x", DoesNotExistOperator, nil, t), getRequirement("x", DoesNotExistOperator, nil, t),
getRequirement("y", ExistsOperator, nil, t), getRequirement("y", ExistsOperator, nil, t),
}, true}, }, true},
{Set{"y": ""}, &LabelSelector{ {Set{"y": ""}, &internalSelector{
getRequirement("x", NotInOperator, sets.NewString(""), t), getRequirement("x", NotInOperator, sets.NewString(""), t),
getRequirement("y", DoesNotExistOperator, nil, t), getRequirement("y", DoesNotExistOperator, nil, t),
}, false}, }, false},
{Set{"y": "baz"}, &LabelSelector{ {Set{"y": "baz"}, &internalSelector{
getRequirement("x", InOperator, sets.NewString(""), t), getRequirement("x", InOperator, sets.NewString(""), t),
}, false}, }, false},
} }
@ -400,75 +401,75 @@ func TestSetSelectorParser(t *testing.T) {
Match bool Match bool
Valid bool Valid bool
}{ }{
{"", LabelSelector(nil), true, true}, {"", NewSelector(), true, true},
{"\rx", LabelSelector{ {"\rx", internalSelector{
getRequirement("x", ExistsOperator, nil, t), getRequirement("x", ExistsOperator, nil, t),
}, true, true}, }, true, true},
{"this-is-a-dns.domain.com/key-with-dash", LabelSelector{ {"this-is-a-dns.domain.com/key-with-dash", internalSelector{
getRequirement("this-is-a-dns.domain.com/key-with-dash", ExistsOperator, nil, t), getRequirement("this-is-a-dns.domain.com/key-with-dash", ExistsOperator, nil, t),
}, true, true}, }, true, true},
{"this-is-another-dns.domain.com/key-with-dash in (so,what)", LabelSelector{ {"this-is-another-dns.domain.com/key-with-dash in (so,what)", internalSelector{
getRequirement("this-is-another-dns.domain.com/key-with-dash", InOperator, sets.NewString("so", "what"), t), getRequirement("this-is-another-dns.domain.com/key-with-dash", InOperator, sets.NewString("so", "what"), t),
}, true, true}, }, true, true},
{"0.1.2.domain/99 notin (10.10.100.1, tick.tack.clock)", LabelSelector{ {"0.1.2.domain/99 notin (10.10.100.1, tick.tack.clock)", internalSelector{
getRequirement("0.1.2.domain/99", NotInOperator, sets.NewString("10.10.100.1", "tick.tack.clock"), t), getRequirement("0.1.2.domain/99", NotInOperator, sets.NewString("10.10.100.1", "tick.tack.clock"), t),
}, true, true}, }, true, true},
{"foo in (abc)", LabelSelector{ {"foo in (abc)", internalSelector{
getRequirement("foo", InOperator, sets.NewString("abc"), t), getRequirement("foo", InOperator, sets.NewString("abc"), t),
}, true, true}, }, true, true},
{"x notin\n (abc)", LabelSelector{ {"x notin\n (abc)", internalSelector{
getRequirement("x", NotInOperator, sets.NewString("abc"), t), getRequirement("x", NotInOperator, sets.NewString("abc"), t),
}, true, true}, }, true, true},
{"x notin \t (abc,def)", LabelSelector{ {"x notin \t (abc,def)", internalSelector{
getRequirement("x", NotInOperator, sets.NewString("abc", "def"), t), getRequirement("x", NotInOperator, sets.NewString("abc", "def"), t),
}, true, true}, }, true, true},
{"x in (abc,def)", LabelSelector{ {"x in (abc,def)", internalSelector{
getRequirement("x", InOperator, sets.NewString("abc", "def"), t), getRequirement("x", InOperator, sets.NewString("abc", "def"), t),
}, true, true}, }, true, true},
{"x in (abc,)", LabelSelector{ {"x in (abc,)", internalSelector{
getRequirement("x", InOperator, sets.NewString("abc", ""), t), getRequirement("x", InOperator, sets.NewString("abc", ""), t),
}, true, true}, }, true, true},
{"x in ()", LabelSelector{ {"x in ()", internalSelector{
getRequirement("x", InOperator, sets.NewString(""), t), getRequirement("x", InOperator, sets.NewString(""), t),
}, true, true}, }, true, true},
{"x notin (abc,,def),bar,z in (),w", LabelSelector{ {"x notin (abc,,def),bar,z in (),w", internalSelector{
getRequirement("bar", ExistsOperator, nil, t), getRequirement("bar", ExistsOperator, nil, t),
getRequirement("w", ExistsOperator, nil, t), getRequirement("w", ExistsOperator, nil, t),
getRequirement("x", NotInOperator, sets.NewString("abc", "", "def"), t), getRequirement("x", NotInOperator, sets.NewString("abc", "", "def"), t),
getRequirement("z", InOperator, sets.NewString(""), t), getRequirement("z", InOperator, sets.NewString(""), t),
}, true, true}, }, true, true},
{"x,y in (a)", LabelSelector{ {"x,y in (a)", internalSelector{
getRequirement("y", InOperator, sets.NewString("a"), t), getRequirement("y", InOperator, sets.NewString("a"), t),
getRequirement("x", ExistsOperator, nil, t), getRequirement("x", ExistsOperator, nil, t),
}, false, true}, }, false, true},
{"x=a", LabelSelector{ {"x=a", internalSelector{
getRequirement("x", EqualsOperator, sets.NewString("a"), t), getRequirement("x", EqualsOperator, sets.NewString("a"), t),
}, true, true}, }, true, true},
{"x=a,y!=b", LabelSelector{ {"x=a,y!=b", internalSelector{
getRequirement("x", EqualsOperator, sets.NewString("a"), t), getRequirement("x", EqualsOperator, sets.NewString("a"), t),
getRequirement("y", NotEqualsOperator, sets.NewString("b"), t), getRequirement("y", NotEqualsOperator, sets.NewString("b"), t),
}, true, true}, }, true, true},
{"x=a,y!=b,z in (h,i,j)", LabelSelector{ {"x=a,y!=b,z in (h,i,j)", internalSelector{
getRequirement("x", EqualsOperator, sets.NewString("a"), t), getRequirement("x", EqualsOperator, sets.NewString("a"), t),
getRequirement("y", NotEqualsOperator, sets.NewString("b"), t), getRequirement("y", NotEqualsOperator, sets.NewString("b"), t),
getRequirement("z", InOperator, sets.NewString("h", "i", "j"), t), getRequirement("z", InOperator, sets.NewString("h", "i", "j"), t),
}, true, true}, }, true, true},
{"x=a||y=b", LabelSelector{}, false, false}, {"x=a||y=b", internalSelector{}, false, false},
{"x,,y", nil, true, false}, {"x,,y", nil, true, false},
{",x,y", nil, true, false}, {",x,y", nil, true, false},
{"x nott in (y)", nil, true, false}, {"x nott in (y)", nil, true, false},
{"x notin ( )", LabelSelector{ {"x notin ( )", internalSelector{
getRequirement("x", NotInOperator, sets.NewString(""), t), getRequirement("x", NotInOperator, sets.NewString(""), t),
}, true, true}, }, true, true},
{"x notin (, a)", LabelSelector{ {"x notin (, a)", internalSelector{
getRequirement("x", NotInOperator, sets.NewString("", "a"), t), getRequirement("x", NotInOperator, sets.NewString("", "a"), t),
}, true, true}, }, true, true},
{"a in (xyz),", nil, true, false}, {"a in (xyz),", nil, true, false},
{"a in (xyz)b notin ()", nil, true, false}, {"a in (xyz)b notin ()", nil, true, false},
{"a ", LabelSelector{ {"a ", internalSelector{
getRequirement("a", ExistsOperator, nil, t), getRequirement("a", ExistsOperator, nil, t),
}, true, true}, }, true, true},
{"a in (x,y,notin, z,in)", LabelSelector{ {"a in (x,y,notin, z,in)", internalSelector{
getRequirement("a", InOperator, sets.NewString("in", "notin", "x", "y", "z"), t), getRequirement("a", InOperator, sets.NewString("in", "notin", "x", "y", "z"), t),
}, true, true}, // operator 'in' inside list of identifiers }, true, true}, // operator 'in' inside list of identifiers
{"a in (xyz abc)", nil, false, false}, // no comma {"a in (xyz abc)", nil, false, false}, // no comma
@ -483,7 +484,7 @@ func TestSetSelectorParser(t *testing.T) {
} else if err == nil && !ssp.Valid { } else if err == nil && !ssp.Valid {
t.Errorf("Parse(%s) => %+v expected error", ssp.In, sel) t.Errorf("Parse(%s) => %+v expected error", ssp.In, sel)
} else if ssp.Match && !reflect.DeepEqual(sel, ssp.Out) { } else if ssp.Match && !reflect.DeepEqual(sel, ssp.Out) {
t.Errorf("Parse(%s) => parse output '%v' doesn't match '%v' expected match", ssp.In, sel, ssp.Out) t.Errorf("Parse(%s) => parse output '%#v' doesn't match '%#v' expected match", ssp.In, sel, ssp.Out)
} }
} }
} }
@ -499,6 +500,7 @@ func getRequirement(key string, op Operator, vals sets.String, t *testing.T) Req
func TestAdd(t *testing.T) { func TestAdd(t *testing.T) {
testCases := []struct { testCases := []struct {
name string
sel Selector sel Selector
key string key string
operator Operator operator Operator
@ -506,27 +508,33 @@ func TestAdd(t *testing.T) {
refSelector Selector refSelector Selector
}{ }{
{ {
LabelSelector{}, "keyInOperator",
internalSelector{},
"key", "key",
InOperator, InOperator,
[]string{"value"}, []string{"value"},
LabelSelector{Requirement{"key", InOperator, sets.NewString("value")}}, internalSelector{Requirement{"key", InOperator, sets.NewString("value")}},
}, },
{ {
LabelSelector{Requirement{"key", InOperator, sets.NewString("value")}}, "keyEqualsOperator",
internalSelector{Requirement{"key", InOperator, sets.NewString("value")}},
"key2", "key2",
EqualsOperator, EqualsOperator,
[]string{"value2"}, []string{"value2"},
LabelSelector{ internalSelector{
Requirement{"key", InOperator, sets.NewString("value")}, Requirement{"key", InOperator, sets.NewString("value")},
Requirement{"key2", EqualsOperator, sets.NewString("value2")}, Requirement{"key2", EqualsOperator, sets.NewString("value2")},
}, },
}, },
} }
for _, ts := range testCases { for _, ts := range testCases {
ts.sel = ts.sel.Add(ts.key, ts.operator, ts.values) req, err := NewRequirement(ts.key, ts.operator, sets.NewString(ts.values...))
if err != nil {
t.Errorf("%s - Unable to create labels.Requirement", ts.name)
}
ts.sel = ts.sel.Add(*req)
if !reflect.DeepEqual(ts.sel, ts.refSelector) { if !reflect.DeepEqual(ts.sel, ts.refSelector) {
t.Errorf("Expected %v found %v", ts.refSelector, ts.sel) t.Errorf("%s - Expected %v found %v", ts.name, ts.refSelector, ts.sel)
} }
} }
} }