mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-09-14 13:45:06 +00:00
Merge pull request #30658 from hongchaodeng/r2
Automatic merge from submit-queue Make labels, fields expose selectable requirements What? This is to change the labels/fields Selector interface and make them expose selectable requirements. We reuse labels.Requirement struct for label selector and add fields.Requirement for field selector. Why? In order to index labels/fields, we need them to tell us three things: index key (a field or a label), operator (greater, less, or equal), and value (string, int, etc.). By getting selectable requirements, we are able to pass them down and use them for indexing in storage layer.
This commit is contained in:
@@ -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)
|
||||
}
|
||||
|
@@ -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:
|
||||
|
30
pkg/fields/requirements.go
Normal file
30
pkg/fields/requirements.go
Normal file
@@ -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
|
||||
}
|
@@ -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 {
|
||||
|
@@ -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.
|
||||
@@ -54,28 +64,13 @@ func (n nothingSelector) Matches(_ Labels) bool { return false }
|
||||
func (n nothingSelector) Empty() bool { return false }
|
||||
func (n nothingSelector) String() string { return "<null>" }
|
||||
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 {
|
||||
|
@@ -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")},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@@ -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")
|
||||
}
|
||||
|
33
pkg/selection/operator.go
Normal file
33
pkg/selection/operator.go
Normal file
@@ -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"
|
||||
)
|
Reference in New Issue
Block a user