diff --git a/pkg/api/helpers.go b/pkg/api/helpers.go index 28fe81b959..617d49c46c 100644 --- a/pkg/api/helpers.go +++ b/pkg/api/helpers.go @@ -30,6 +30,7 @@ import ( "k8s.io/kubernetes/pkg/fields" "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/runtime" + "k8s.io/kubernetes/pkg/selection" "k8s.io/kubernetes/pkg/types" "k8s.io/kubernetes/pkg/util/sets" @@ -383,20 +384,20 @@ func NodeSelectorRequirementsAsSelector(nsm []NodeSelectorRequirement) (labels.S } selector := labels.NewSelector() for _, expr := range nsm { - var op labels.Operator + var op selection.Operator switch expr.Operator { case NodeSelectorOpIn: - op = labels.InOperator + op = selection.In case NodeSelectorOpNotIn: - op = labels.NotInOperator + op = selection.NotIn case NodeSelectorOpExists: - op = labels.ExistsOperator + op = selection.Exists case NodeSelectorOpDoesNotExist: - op = labels.DoesNotExistOperator + op = selection.DoesNotExist case NodeSelectorOpGt: - op = labels.GreaterThanOperator + op = selection.GreaterThan case NodeSelectorOpLt: - op = labels.LessThanOperator + op = selection.LessThan default: return nil, fmt.Errorf("%q is not a valid node selector operator", expr.Operator) } diff --git a/pkg/api/unversioned/helpers.go b/pkg/api/unversioned/helpers.go index cb2f2c5cfd..5bd9051cbc 100644 --- a/pkg/api/unversioned/helpers.go +++ b/pkg/api/unversioned/helpers.go @@ -20,6 +20,7 @@ import ( "fmt" "k8s.io/kubernetes/pkg/labels" + "k8s.io/kubernetes/pkg/selection" "k8s.io/kubernetes/pkg/util/sets" ) @@ -35,23 +36,23 @@ func LabelSelectorAsSelector(ps *LabelSelector) (labels.Selector, error) { } selector := labels.NewSelector() for k, v := range ps.MatchLabels { - r, err := labels.NewRequirement(k, labels.EqualsOperator, sets.NewString(v)) + r, err := labels.NewRequirement(k, selection.Equals, sets.NewString(v)) if err != nil { return nil, err } selector = selector.Add(*r) } for _, expr := range ps.MatchExpressions { - var op labels.Operator + var op selection.Operator switch expr.Operator { case LabelSelectorOpIn: - op = labels.InOperator + op = selection.In case LabelSelectorOpNotIn: - op = labels.NotInOperator + op = selection.NotIn case LabelSelectorOpExists: - op = labels.ExistsOperator + op = selection.Exists case LabelSelectorOpDoesNotExist: - op = labels.DoesNotExistOperator + op = selection.DoesNotExist default: return nil, fmt.Errorf("%q is not a valid pod selector operator", expr.Operator) } @@ -108,7 +109,7 @@ func ParseToLabelSelector(selector string) (*LabelSelector, error) { for _, req := range reqs { var op LabelSelectorOperator switch req.Operator() { - case labels.EqualsOperator, labels.DoubleEqualsOperator: + case selection.Equals, selection.DoubleEquals: vals := req.Values() if vals.Len() != 1 { return nil, fmt.Errorf("equals operator must have exactly one value") @@ -119,15 +120,15 @@ func ParseToLabelSelector(selector string) (*LabelSelector, error) { } labelSelector.MatchLabels[req.Key()] = val continue - case labels.InOperator: + case selection.In: op = LabelSelectorOpIn - case labels.NotInOperator: + case selection.NotIn: op = LabelSelectorOpNotIn - case labels.ExistsOperator: + case selection.Exists: op = LabelSelectorOpExists - case labels.DoesNotExistOperator: + case selection.DoesNotExist: op = LabelSelectorOpDoesNotExist - case labels.GreaterThanOperator, labels.LessThanOperator: + case selection.GreaterThan, selection.LessThan: // Adding a separate case for these operators to indicate that this is deliberate return nil, fmt.Errorf("%q isn't supported in label selectors", req.Operator()) default: diff --git a/pkg/fields/requirements.go b/pkg/fields/requirements.go new file mode 100644 index 0000000000..33c6e4e1a8 --- /dev/null +++ b/pkg/fields/requirements.go @@ -0,0 +1,30 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package fields + +import "k8s.io/kubernetes/pkg/selection" + +// Requirements is AND of all requirements. +type Requirements []Requirement + +// Requirement contains a field, a value, and an operator that relates the field and value. +// This is currently for reading internal selection information of field selector. +type Requirement struct { + Operator selection.Operator + Field string + Value string +} diff --git a/pkg/fields/selector.go b/pkg/fields/selector.go index eef44d3563..75161daf1d 100644 --- a/pkg/fields/selector.go +++ b/pkg/fields/selector.go @@ -20,6 +20,8 @@ import ( "fmt" "sort" "strings" + + "k8s.io/kubernetes/pkg/selection" ) // Selector represents a field selector. @@ -39,6 +41,10 @@ type Selector interface { // applied to the entire selector, or an error if fn returns an error. Transform(fn TransformFunc) (Selector, error) + // Requirements converts this interface to Requirements to expose + // more detailed selection information. + Requirements() Requirements + // String returns a human readable string that represents this selector. String() string } @@ -75,6 +81,14 @@ func (t *hasTerm) Transform(fn TransformFunc) (Selector, error) { return &hasTerm{field, value}, nil } +func (t *hasTerm) Requirements() Requirements { + return []Requirement{{ + Field: t.field, + Operator: selection.Equals, + Value: t.value, + }} +} + func (t *hasTerm) String() string { return fmt.Sprintf("%v=%v", t.field, t.value) } @@ -103,6 +117,14 @@ func (t *notHasTerm) Transform(fn TransformFunc) (Selector, error) { return ¬HasTerm{field, value}, nil } +func (t *notHasTerm) Requirements() Requirements { + return []Requirement{{ + Field: t.field, + Operator: selection.NotEquals, + Value: t.value, + }} +} + func (t *notHasTerm) String() string { return fmt.Sprintf("%v!=%v", t.field, t.value) } @@ -157,6 +179,15 @@ func (t andTerm) Transform(fn TransformFunc) (Selector, error) { return andTerm(next), nil } +func (t andTerm) Requirements() Requirements { + reqs := make([]Requirement, 0, len(t)) + for _, s := range []Selector(t) { + rs := s.Requirements() + reqs = append(reqs, rs...) + } + return reqs +} + func (t andTerm) String() string { var terms []string for _, q := range t { diff --git a/pkg/labels/selector.go b/pkg/labels/selector.go index 64dd420e48..6551aba601 100644 --- a/pkg/labels/selector.go +++ b/pkg/labels/selector.go @@ -24,10 +24,14 @@ import ( "strings" "github.com/golang/glog" + "k8s.io/kubernetes/pkg/selection" "k8s.io/kubernetes/pkg/util/sets" "k8s.io/kubernetes/pkg/util/validation" ) +// Requirements is AND of all requirements. +type Requirements []Requirement + // Selector represents a label selector. type Selector interface { // Matches returns true if this selector matches the given set of labels. @@ -41,6 +45,12 @@ type Selector interface { // Add adds requirements to the Selector Add(r ...Requirement) Selector + + // Requirements converts this interface into Requirements to expose + // more detailed selection information. + // If there are querying parameters, it will return converted requirements and selectable=true. + // If this selector doesn't want to select anything, it will return selectable=false. + Requirements() (requirements Requirements, selectable bool) } // Everything returns a selector that matches all labels. @@ -50,32 +60,17 @@ func Everything() Selector { type nothingSelector struct{} -func (n nothingSelector) Matches(_ Labels) bool { return false } -func (n nothingSelector) Empty() bool { return false } -func (n nothingSelector) String() string { return "" } -func (n nothingSelector) Add(_ ...Requirement) Selector { return n } +func (n nothingSelector) Matches(_ Labels) bool { return false } +func (n nothingSelector) Empty() bool { return false } +func (n nothingSelector) String() string { return "" } +func (n nothingSelector) Add(_ ...Requirement) Selector { return n } +func (n nothingSelector) Requirements() (Requirements, bool) { return nil, false } // Nothing returns a selector that matches no labels func Nothing() Selector { return nothingSelector{} } -// Operator represents a key's relationship -// to a set of values in a Requirement. -type Operator string - -const ( - DoesNotExistOperator Operator = "!" - EqualsOperator Operator = "=" - DoubleEqualsOperator Operator = "==" - InOperator Operator = "in" - NotEqualsOperator Operator = "!=" - NotInOperator Operator = "notin" - ExistsOperator Operator = "exists" - GreaterThanOperator Operator = "gt" - LessThanOperator Operator = "lt" -) - func NewSelector() Selector { return internalSelector(nil) } @@ -91,14 +86,13 @@ func (a ByKey) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func (a ByKey) Less(i, j int) bool { return a[i].key < a[j].key } -// Requirement is a selector that contains values, a key -// and an operator that relates the key and values. The zero -// value of Requirement is invalid. +// Requirement contains values, a key, and an operator that relates the key and values. +// The zero value of Requirement is invalid. // Requirement implements both set based match and exact match -// Requirement is initialized via NewRequirement constructor for creating a valid Requirement. +// Requirement should be initialized via NewRequirement constructor for creating a valid Requirement. type Requirement struct { key string - operator Operator + operator selection.Operator strValues sets.String } @@ -113,24 +107,24 @@ type Requirement struct { // of characters. See validateLabelKey for more details. // // The empty string is a valid value in the input values set. -func NewRequirement(key string, op Operator, vals sets.String) (*Requirement, error) { +func NewRequirement(key string, op selection.Operator, vals sets.String) (*Requirement, error) { if err := validateLabelKey(key); err != nil { return nil, err } switch op { - case InOperator, NotInOperator: + case selection.In, selection.NotIn: if len(vals) == 0 { return nil, fmt.Errorf("for 'in', 'notin' operators, values set can't be empty") } - case EqualsOperator, DoubleEqualsOperator, NotEqualsOperator: + case selection.Equals, selection.DoubleEquals, selection.NotEquals: if len(vals) != 1 { return nil, fmt.Errorf("exact-match compatibility requires one single value") } - case ExistsOperator, DoesNotExistOperator: + case selection.Exists, selection.DoesNotExist: if len(vals) != 0 { return nil, fmt.Errorf("values set must be empty for exists and does not exist") } - case GreaterThanOperator, LessThanOperator: + case selection.GreaterThan, selection.LessThan: if len(vals) != 1 { return nil, fmt.Errorf("for 'Gt', 'Lt' operators, exactly one value is required") } @@ -164,21 +158,21 @@ func NewRequirement(key string, op Operator, vals sets.String) (*Requirement, er // the Requirement's key and the corresponding value satisfies mathematical inequality. func (r *Requirement) Matches(ls Labels) bool { switch r.operator { - case InOperator, EqualsOperator, DoubleEqualsOperator: + case selection.In, selection.Equals, selection.DoubleEquals: if !ls.Has(r.key) { return false } return r.strValues.Has(ls.Get(r.key)) - case NotInOperator, NotEqualsOperator: + case selection.NotIn, selection.NotEquals: if !ls.Has(r.key) { return true } return !r.strValues.Has(ls.Get(r.key)) - case ExistsOperator: + case selection.Exists: return ls.Has(r.key) - case DoesNotExistOperator: + case selection.DoesNotExist: return !ls.Has(r.key) - case GreaterThanOperator, LessThanOperator: + case selection.GreaterThan, selection.LessThan: if !ls.Has(r.key) { return false } @@ -202,7 +196,7 @@ func (r *Requirement) Matches(ls Labels) bool { return false } } - return (r.operator == GreaterThanOperator && lsValue > rValue) || (r.operator == LessThanOperator && lsValue < rValue) + return (r.operator == selection.GreaterThan && lsValue > rValue) || (r.operator == selection.LessThan && lsValue < rValue) default: return false } @@ -211,7 +205,7 @@ func (r *Requirement) Matches(ls Labels) bool { func (r *Requirement) Key() string { return r.key } -func (r *Requirement) Operator() Operator { +func (r *Requirement) Operator() selection.Operator { return r.operator } func (r *Requirement) Values() sets.String { @@ -235,32 +229,32 @@ func (lsel internalSelector) Empty() bool { // returned. See NewRequirement for creating a valid Requirement. func (r *Requirement) String() string { var buffer bytes.Buffer - if r.operator == DoesNotExistOperator { + if r.operator == selection.DoesNotExist { buffer.WriteString("!") } buffer.WriteString(r.key) switch r.operator { - case EqualsOperator: + case selection.Equals: buffer.WriteString("=") - case DoubleEqualsOperator: + case selection.DoubleEquals: buffer.WriteString("==") - case NotEqualsOperator: + case selection.NotEquals: buffer.WriteString("!=") - case InOperator: + case selection.In: buffer.WriteString(" in ") - case NotInOperator: + case selection.NotIn: buffer.WriteString(" notin ") - case GreaterThanOperator: + case selection.GreaterThan: buffer.WriteString(">") - case LessThanOperator: + case selection.LessThan: buffer.WriteString("<") - case ExistsOperator, DoesNotExistOperator: + case selection.Exists, selection.DoesNotExist: return buffer.String() } switch r.operator { - case InOperator, NotInOperator: + case selection.In, selection.NotIn: buffer.WriteString("(") } if len(r.strValues) == 1 { @@ -270,7 +264,7 @@ func (r *Requirement) String() string { } switch r.operator { - case InOperator, NotInOperator: + case selection.In, selection.NotIn: buffer.WriteString(")") } return buffer.String() @@ -301,6 +295,8 @@ func (lsel internalSelector) Matches(l Labels) bool { return true } +func (lsel internalSelector) Requirements() (Requirements, bool) { return Requirements(lsel), true } + // String returns a comma-separated string of all // the internalSelector Requirements' human-readable strings. func (lsel internalSelector) String() string { @@ -564,7 +560,7 @@ func (p *Parser) parseRequirement() (*Requirement, error) { if err != nil { return nil, err } - if operator == ExistsOperator || operator == DoesNotExistOperator { // operator found lookahead set checked + if operator == selection.Exists || operator == selection.DoesNotExist { // operator found lookahead set checked return NewRequirement(key, operator, nil) } operator, err = p.parseOperator() @@ -573,9 +569,9 @@ func (p *Parser) parseRequirement() (*Requirement, error) { } var values sets.String switch operator { - case InOperator, NotInOperator: + case selection.In, selection.NotIn: values, err = p.parseValues() - case EqualsOperator, DoubleEqualsOperator, NotEqualsOperator, GreaterThanOperator, LessThanOperator: + case selection.Equals, selection.DoubleEquals, selection.NotEquals, selection.GreaterThan, selection.LessThan: values, err = p.parseExactValue() } if err != nil { @@ -588,11 +584,11 @@ func (p *Parser) parseRequirement() (*Requirement, error) { // parseKeyAndInferOperator parse literals. // in case of no operator '!, in, notin, ==, =, !=' are found // the 'exists' operator is inferred -func (p *Parser) parseKeyAndInferOperator() (string, Operator, error) { - var operator Operator +func (p *Parser) parseKeyAndInferOperator() (string, selection.Operator, error) { + var operator selection.Operator tok, literal := p.consume(Values) if tok == DoesNotExistToken { - operator = DoesNotExistOperator + operator = selection.DoesNotExist tok, literal = p.consume(Values) } if tok != IdentifierToken { @@ -603,8 +599,8 @@ func (p *Parser) parseKeyAndInferOperator() (string, Operator, error) { return "", "", err } if t, _ := p.lookahead(Values); t == EndOfStringToken || t == CommaToken { - if operator != DoesNotExistOperator { - operator = ExistsOperator + if operator != selection.DoesNotExist { + operator = selection.Exists } } return literal, operator, nil @@ -612,24 +608,24 @@ func (p *Parser) parseKeyAndInferOperator() (string, Operator, error) { // parseOperator return operator and eventually matchType // matchType can be exact -func (p *Parser) parseOperator() (op Operator, err error) { +func (p *Parser) parseOperator() (op selection.Operator, err error) { tok, lit := p.consume(KeyAndOperator) switch tok { // DoesNotExistToken shouldn't be here because it's a unary operator, not a binary operator case InToken: - op = InOperator + op = selection.In case EqualsToken: - op = EqualsOperator + op = selection.Equals case DoubleEqualsToken: - op = DoubleEqualsOperator + op = selection.DoubleEquals case GreaterThanToken: - op = GreaterThanOperator + op = selection.GreaterThan case LessThanToken: - op = LessThanOperator + op = selection.LessThan case NotInToken: - op = NotInOperator + op = selection.NotIn case NotEqualsToken: - op = NotEqualsOperator + op = selection.NotEquals default: return "", fmt.Errorf("found '%s', expected: '=', '!=', '==', 'in', notin'", lit) } @@ -788,7 +784,7 @@ func SelectorFromSet(ls Set) Selector { } var requirements internalSelector for label, value := range ls { - if r, err := NewRequirement(label, EqualsOperator, sets.NewString(value)); err != nil { + if r, err := NewRequirement(label, selection.Equals, sets.NewString(value)); err != nil { //TODO: double check errors when input comes from serialization? return internalSelector{} } else { diff --git a/pkg/labels/selector_test.go b/pkg/labels/selector_test.go index 5de69dacc1..76987d7e13 100644 --- a/pkg/labels/selector_test.go +++ b/pkg/labels/selector_test.go @@ -21,6 +21,7 @@ import ( "strings" "testing" + "k8s.io/kubernetes/pkg/selection" "k8s.io/kubernetes/pkg/util/sets" ) @@ -300,23 +301,23 @@ func TestParserLookahead(t *testing.T) { func TestRequirementConstructor(t *testing.T) { requirementConstructorTests := []struct { Key string - Op Operator + Op selection.Operator Vals sets.String Success bool }{ - {"x", InOperator, nil, false}, - {"x", NotInOperator, sets.NewString(), false}, - {"x", InOperator, sets.NewString("foo"), true}, - {"x", NotInOperator, sets.NewString("foo"), true}, - {"x", ExistsOperator, nil, true}, - {"x", DoesNotExistOperator, nil, true}, - {"1foo", InOperator, sets.NewString("bar"), true}, - {"1234", InOperator, sets.NewString("bar"), true}, - {"y", GreaterThanOperator, sets.NewString("1"), true}, - {"z", LessThanOperator, sets.NewString("6"), true}, - {"foo", GreaterThanOperator, sets.NewString("bar"), false}, - {"barz", LessThanOperator, sets.NewString("blah"), false}, - {strings.Repeat("a", 254), ExistsOperator, nil, false}, //breaks DNS rule that len(key) <= 253 + {"x", selection.In, nil, false}, + {"x", selection.NotIn, sets.NewString(), false}, + {"x", selection.In, sets.NewString("foo"), true}, + {"x", selection.NotIn, sets.NewString("foo"), true}, + {"x", selection.Exists, nil, true}, + {"x", selection.DoesNotExist, nil, true}, + {"1foo", selection.In, sets.NewString("bar"), true}, + {"1234", selection.In, sets.NewString("bar"), true}, + {"y", selection.GreaterThan, sets.NewString("1"), true}, + {"z", selection.LessThan, sets.NewString("6"), true}, + {"foo", selection.GreaterThan, sets.NewString("bar"), false}, + {"barz", selection.LessThan, sets.NewString("blah"), false}, + {strings.Repeat("a", 254), selection.Exists, nil, false}, //breaks DNS rule that len(key) <= 253 } for _, rc := range requirementConstructorTests { if _, err := NewRequirement(rc.Key, rc.Op, rc.Vals); err == nil && !rc.Success { @@ -336,34 +337,34 @@ func TestToString(t *testing.T) { }{ {&internalSelector{ - getRequirement("x", InOperator, sets.NewString("abc", "def"), t), - getRequirement("y", NotInOperator, sets.NewString("jkl"), t), - getRequirement("z", ExistsOperator, nil, t)}, + getRequirement("x", selection.In, sets.NewString("abc", "def"), t), + getRequirement("y", selection.NotIn, sets.NewString("jkl"), t), + getRequirement("z", selection.Exists, nil, t)}, "x in (abc,def),y notin (jkl),z", true}, {&internalSelector{ - getRequirement("x", NotInOperator, sets.NewString("abc", "def"), t), - getRequirement("y", NotEqualsOperator, sets.NewString("jkl"), t), - getRequirement("z", DoesNotExistOperator, nil, t)}, + getRequirement("x", selection.NotIn, sets.NewString("abc", "def"), t), + getRequirement("y", selection.NotEquals, sets.NewString("jkl"), t), + getRequirement("z", selection.DoesNotExist, nil, t)}, "x notin (abc,def),y!=jkl,!z", true}, {&internalSelector{ - getRequirement("x", InOperator, sets.NewString("abc", "def"), t), + getRequirement("x", selection.In, sets.NewString("abc", "def"), t), req}, // adding empty req for the trailing ',' "x in (abc,def),", false}, {&internalSelector{ - getRequirement("x", NotInOperator, sets.NewString("abc"), t), - getRequirement("y", InOperator, sets.NewString("jkl", "mno"), t), - getRequirement("z", NotInOperator, sets.NewString(""), t)}, + getRequirement("x", selection.NotIn, sets.NewString("abc"), t), + getRequirement("y", selection.In, sets.NewString("jkl", "mno"), t), + getRequirement("z", selection.NotIn, sets.NewString(""), t)}, "x notin (abc),y in (jkl,mno),z notin ()", true}, {&internalSelector{ - getRequirement("x", EqualsOperator, sets.NewString("abc"), t), - getRequirement("y", DoubleEqualsOperator, sets.NewString("jkl"), t), - getRequirement("z", NotEqualsOperator, sets.NewString("a"), t), - getRequirement("z", ExistsOperator, nil, t)}, + getRequirement("x", selection.Equals, sets.NewString("abc"), t), + getRequirement("y", selection.DoubleEquals, sets.NewString("jkl"), t), + getRequirement("z", selection.NotEquals, sets.NewString("a"), t), + getRequirement("z", selection.Exists, nil, t)}, "x=abc,y==jkl,z!=a,z", true}, {&internalSelector{ - getRequirement("x", GreaterThanOperator, sets.NewString("2"), t), - getRequirement("y", LessThanOperator, sets.NewString("8"), t), - getRequirement("z", ExistsOperator, nil, t)}, + getRequirement("x", selection.GreaterThan, sets.NewString("2"), t), + getRequirement("y", selection.LessThan, sets.NewString("8"), t), + getRequirement("z", selection.Exists, nil, t)}, "x>2,y<8,z", true}, } for _, ts := range toStringTests { @@ -386,33 +387,33 @@ func TestRequirementSelectorMatching(t *testing.T) { req, }, false}, {Set{"x": "foo", "y": "baz"}, &internalSelector{ - getRequirement("x", InOperator, sets.NewString("foo"), t), - getRequirement("y", NotInOperator, sets.NewString("alpha"), t), + getRequirement("x", selection.In, sets.NewString("foo"), t), + getRequirement("y", selection.NotIn, sets.NewString("alpha"), t), }, true}, {Set{"x": "foo", "y": "baz"}, &internalSelector{ - getRequirement("x", InOperator, sets.NewString("foo"), t), - getRequirement("y", InOperator, sets.NewString("alpha"), t), + getRequirement("x", selection.In, sets.NewString("foo"), t), + getRequirement("y", selection.In, sets.NewString("alpha"), t), }, false}, {Set{"y": ""}, &internalSelector{ - getRequirement("x", NotInOperator, sets.NewString(""), t), - getRequirement("y", ExistsOperator, nil, t), + getRequirement("x", selection.NotIn, sets.NewString(""), t), + getRequirement("y", selection.Exists, nil, t), }, true}, {Set{"y": ""}, &internalSelector{ - getRequirement("x", DoesNotExistOperator, nil, t), - getRequirement("y", ExistsOperator, nil, t), + getRequirement("x", selection.DoesNotExist, nil, t), + getRequirement("y", selection.Exists, nil, t), }, true}, {Set{"y": ""}, &internalSelector{ - getRequirement("x", NotInOperator, sets.NewString(""), t), - getRequirement("y", DoesNotExistOperator, nil, t), + getRequirement("x", selection.NotIn, sets.NewString(""), t), + getRequirement("y", selection.DoesNotExist, nil, t), }, false}, {Set{"y": "baz"}, &internalSelector{ - getRequirement("x", InOperator, sets.NewString(""), t), + getRequirement("x", selection.In, sets.NewString(""), t), }, false}, {Set{"z": "2"}, &internalSelector{ - getRequirement("z", GreaterThanOperator, sets.NewString("1"), t), + getRequirement("z", selection.GreaterThan, sets.NewString("1"), t), }, true}, {Set{"z": "v2"}, &internalSelector{ - getRequirement("z", GreaterThanOperator, sets.NewString("1"), t), + getRequirement("z", selection.GreaterThan, sets.NewString("1"), t), }, false}, } for _, lsm := range labelSelectorMatchingTests { @@ -431,80 +432,80 @@ func TestSetSelectorParser(t *testing.T) { }{ {"", NewSelector(), true, true}, {"\rx", internalSelector{ - getRequirement("x", ExistsOperator, nil, t), + getRequirement("x", selection.Exists, nil, t), }, true, true}, {"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", selection.Exists, nil, t), }, true, true}, {"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", selection.In, sets.NewString("so", "what"), t), }, true, true}, {"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", selection.NotIn, sets.NewString("10.10.100.1", "tick.tack.clock"), t), }, true, true}, {"foo in (abc)", internalSelector{ - getRequirement("foo", InOperator, sets.NewString("abc"), t), + getRequirement("foo", selection.In, sets.NewString("abc"), t), }, true, true}, {"x notin\n (abc)", internalSelector{ - getRequirement("x", NotInOperator, sets.NewString("abc"), t), + getRequirement("x", selection.NotIn, sets.NewString("abc"), t), }, true, true}, {"x notin \t (abc,def)", internalSelector{ - getRequirement("x", NotInOperator, sets.NewString("abc", "def"), t), + getRequirement("x", selection.NotIn, sets.NewString("abc", "def"), t), }, true, true}, {"x in (abc,def)", internalSelector{ - getRequirement("x", InOperator, sets.NewString("abc", "def"), t), + getRequirement("x", selection.In, sets.NewString("abc", "def"), t), }, true, true}, {"x in (abc,)", internalSelector{ - getRequirement("x", InOperator, sets.NewString("abc", ""), t), + getRequirement("x", selection.In, sets.NewString("abc", ""), t), }, true, true}, {"x in ()", internalSelector{ - getRequirement("x", InOperator, sets.NewString(""), t), + getRequirement("x", selection.In, sets.NewString(""), t), }, true, true}, {"x notin (abc,,def),bar,z in (),w", internalSelector{ - getRequirement("bar", ExistsOperator, nil, t), - getRequirement("w", ExistsOperator, nil, t), - getRequirement("x", NotInOperator, sets.NewString("abc", "", "def"), t), - getRequirement("z", InOperator, sets.NewString(""), t), + getRequirement("bar", selection.Exists, nil, t), + getRequirement("w", selection.Exists, nil, t), + getRequirement("x", selection.NotIn, sets.NewString("abc", "", "def"), t), + getRequirement("z", selection.In, sets.NewString(""), t), }, true, true}, {"x,y in (a)", internalSelector{ - getRequirement("y", InOperator, sets.NewString("a"), t), - getRequirement("x", ExistsOperator, nil, t), + getRequirement("y", selection.In, sets.NewString("a"), t), + getRequirement("x", selection.Exists, nil, t), }, false, true}, {"x=a", internalSelector{ - getRequirement("x", EqualsOperator, sets.NewString("a"), t), + getRequirement("x", selection.Equals, sets.NewString("a"), t), }, true, true}, {"x>1", internalSelector{ - getRequirement("x", GreaterThanOperator, sets.NewString("1"), t), + getRequirement("x", selection.GreaterThan, sets.NewString("1"), t), }, true, true}, {"x<7", internalSelector{ - getRequirement("x", LessThanOperator, sets.NewString("7"), t), + getRequirement("x", selection.LessThan, sets.NewString("7"), t), }, true, true}, {"x=a,y!=b", internalSelector{ - getRequirement("x", EqualsOperator, sets.NewString("a"), t), - getRequirement("y", NotEqualsOperator, sets.NewString("b"), t), + getRequirement("x", selection.Equals, sets.NewString("a"), t), + getRequirement("y", selection.NotEquals, sets.NewString("b"), t), }, true, true}, {"x=a,y!=b,z in (h,i,j)", internalSelector{ - getRequirement("x", EqualsOperator, sets.NewString("a"), t), - getRequirement("y", NotEqualsOperator, sets.NewString("b"), t), - getRequirement("z", InOperator, sets.NewString("h", "i", "j"), t), + getRequirement("x", selection.Equals, sets.NewString("a"), t), + getRequirement("y", selection.NotEquals, sets.NewString("b"), t), + getRequirement("z", selection.In, sets.NewString("h", "i", "j"), t), }, true, true}, {"x=a||y=b", internalSelector{}, false, false}, {"x,,y", nil, true, false}, {",x,y", nil, true, false}, {"x nott in (y)", nil, true, false}, {"x notin ( )", internalSelector{ - getRequirement("x", NotInOperator, sets.NewString(""), t), + getRequirement("x", selection.NotIn, sets.NewString(""), t), }, true, true}, {"x notin (, a)", internalSelector{ - getRequirement("x", NotInOperator, sets.NewString("", "a"), t), + getRequirement("x", selection.NotIn, sets.NewString("", "a"), t), }, true, true}, {"a in (xyz),", nil, true, false}, {"a in (xyz)b notin ()", nil, true, false}, {"a ", internalSelector{ - getRequirement("a", ExistsOperator, nil, t), + getRequirement("a", selection.Exists, nil, t), }, true, true}, {"a in (x,y,notin, z,in)", internalSelector{ - getRequirement("a", InOperator, sets.NewString("in", "notin", "x", "y", "z"), t), + getRequirement("a", selection.In, sets.NewString("in", "notin", "x", "y", "z"), t), }, true, true}, // operator 'in' inside list of identifiers {"a in (xyz abc)", nil, false, false}, // no comma {"a notin(", nil, true, false}, // bad formed @@ -523,7 +524,7 @@ func TestSetSelectorParser(t *testing.T) { } } -func getRequirement(key string, op Operator, vals sets.String, t *testing.T) Requirement { +func getRequirement(key string, op selection.Operator, vals sets.String, t *testing.T) Requirement { req, err := NewRequirement(key, op, vals) if err != nil { t.Errorf("NewRequirement(%v, %v, %v) resulted in error:%v", key, op, vals, err) @@ -537,7 +538,7 @@ func TestAdd(t *testing.T) { name string sel Selector key string - operator Operator + operator selection.Operator values []string refSelector Selector }{ @@ -545,19 +546,19 @@ func TestAdd(t *testing.T) { "keyInOperator", internalSelector{}, "key", - InOperator, + selection.In, []string{"value"}, - internalSelector{Requirement{"key", InOperator, sets.NewString("value")}}, + internalSelector{Requirement{"key", selection.In, sets.NewString("value")}}, }, { "keyEqualsOperator", - internalSelector{Requirement{"key", InOperator, sets.NewString("value")}}, + internalSelector{Requirement{"key", selection.In, sets.NewString("value")}}, "key2", - EqualsOperator, + selection.Equals, []string{"value2"}, internalSelector{ - Requirement{"key", InOperator, sets.NewString("value")}, - Requirement{"key2", EqualsOperator, sets.NewString("value2")}, + Requirement{"key", selection.In, sets.NewString("value")}, + Requirement{"key2", selection.Equals, sets.NewString("value2")}, }, }, } diff --git a/pkg/registry/generic/registry/store_test.go b/pkg/registry/generic/registry/store_test.go index c3eb7a217a..17c4e4491b 100644 --- a/pkg/registry/generic/registry/store_test.go +++ b/pkg/registry/generic/registry/store_test.go @@ -35,6 +35,7 @@ import ( "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/runtime" + "k8s.io/kubernetes/pkg/selection" "k8s.io/kubernetes/pkg/storage" etcdstorage "k8s.io/kubernetes/pkg/storage/etcd" "k8s.io/kubernetes/pkg/storage/etcd/etcdtest" @@ -88,7 +89,7 @@ func NewTestGenericStoreRegistry(t *testing.T) (*etcdtesting.EtcdTestServer, *St 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...)) + l, err := labels.NewRequirement("name", selection.In, sets.NewString(names...)) if err != nil { panic("Labels requirement must validate successfully") } diff --git a/pkg/selection/operator.go b/pkg/selection/operator.go new file mode 100644 index 0000000000..298f798c43 --- /dev/null +++ b/pkg/selection/operator.go @@ -0,0 +1,33 @@ +/* +Copyright 2016 The Kubernetes Authors. + +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 selection + +// Operator represents a key/field's relationship to value(s). +// See labels.Requirement and fields.Requirement for more details. +type Operator string + +const ( + DoesNotExist Operator = "!" + Equals Operator = "=" + DoubleEquals Operator = "==" + In Operator = "in" + NotEquals Operator = "!=" + NotIn Operator = "notin" + Exists Operator = "exists" + GreaterThan Operator = "gt" + LessThan Operator = "lt" +)