2014-06-17 00:49:50 +00:00
/ *
2015-05-01 16:19:44 +00:00
Copyright 2014 The Kubernetes Authors All rights reserved .
2014-06-17 00:49:50 +00:00
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 .
* /
2014-06-17 00:57:57 +00:00
package labels
2014-06-17 00:49:50 +00:00
import (
2014-08-19 03:41:20 +00:00
"bytes"
2014-06-17 00:49:50 +00:00
"fmt"
2014-06-20 17:03:56 +00:00
"sort"
2016-01-26 23:03:18 +00:00
"strconv"
2014-06-17 00:49:50 +00:00
"strings"
2014-08-01 03:56:37 +00:00
2016-01-26 23:03:18 +00:00
"github.com/golang/glog"
2015-09-09 17:45:01 +00:00
"k8s.io/kubernetes/pkg/util/sets"
2015-09-10 22:48:28 +00:00
"k8s.io/kubernetes/pkg/util/validation"
2014-06-17 00:49:50 +00:00
)
2014-07-11 05:07:05 +00:00
// Selector represents a label selector.
2014-06-18 23:47:41 +00:00
type Selector interface {
2014-07-11 05:07:05 +00:00
// Matches returns true if this selector matches the given set of labels.
2014-06-17 00:49:50 +00:00
Matches ( Labels ) bool
2014-07-25 16:15:17 +00:00
// Empty returns true if this selector does not restrict the selection space.
Empty ( ) bool
2014-07-11 05:07:05 +00:00
// String returns a human readable string that represents this selector.
2014-06-17 00:49:50 +00:00
String ( ) string
2015-03-25 15:17:22 +00:00
2015-12-03 08:04:55 +00:00
// Add adds requirements to the Selector
Add ( r ... Requirement ) Selector
2014-06-17 00:49:50 +00:00
}
2014-06-18 23:47:41 +00:00
// Everything returns a selector that matches all labels.
func Everything ( ) Selector {
2015-12-03 08:04:55 +00:00
return internalSelector { }
2014-06-17 00:49:50 +00:00
}
2015-10-14 18:03:59 +00:00
type nothingSelector struct { }
2015-12-03 08:04:55 +00:00
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 }
2015-10-14 18:03:59 +00:00
// Nothing returns a selector that matches no labels
func Nothing ( ) Selector {
return nothingSelector { }
}
2014-08-01 03:56:37 +00:00
// Operator represents a key's relationship
// to a set of values in a Requirement.
2015-02-14 23:07:30 +00:00
type Operator string
2014-07-31 04:29:42 +00:00
const (
2015-10-12 23:13:41 +00:00
DoesNotExistOperator Operator = "!"
2015-02-14 23:07:30 +00:00
EqualsOperator Operator = "="
DoubleEqualsOperator Operator = "=="
InOperator Operator = "in"
NotEqualsOperator Operator = "!="
NotInOperator Operator = "notin"
ExistsOperator Operator = "exists"
2016-01-26 23:03:18 +00:00
GreaterThanOperator Operator = "Gt"
LessThanOperator Operator = "Lt"
2014-07-31 04:29:42 +00:00
)
2015-12-03 08:04:55 +00:00
func NewSelector ( ) Selector {
return internalSelector ( nil )
}
type internalSelector [ ] Requirement
2014-07-31 04:29:42 +00:00
2015-12-03 08:04:55 +00:00
// Sort by key to obtain determisitic parser
2015-02-14 23:07:30 +00:00
type ByKey [ ] Requirement
func ( a ByKey ) Len ( ) int { return len ( a ) }
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 }
2014-08-19 03:41:20 +00:00
// Requirement is a selector that contains values, a key
// and an operator that relates the key and values. The zero
2015-02-14 23:07:30 +00:00
// 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.
2014-07-31 04:29:42 +00:00
type Requirement struct {
2014-08-01 03:56:37 +00:00
key string
operator Operator
2015-09-09 17:45:01 +00:00
strValues sets . String
2014-07-31 04:29:42 +00:00
}
2014-08-19 03:41:20 +00:00
// NewRequirement is the constructor for a Requirement.
2014-10-28 03:03:07 +00:00
// If any of these rules is violated, an error is returned:
2015-10-12 23:13:41 +00:00
// (1) The operator can only be In, NotIn, Equals, DoubleEquals, NotEquals, Exists, or DoesNotExist.
// (2) If the operator is In or NotIn, the values set must be non-empty.
// (3) If the operator is Equals, DoubleEquals, or NotEquals, the values set must contain one value.
// (4) If the operator is Exists or DoesNotExist, the value set must be empty.
2016-01-26 23:03:18 +00:00
// (5) If the operator is Gt or Lt, the values set must contain only one value.
// (6) The key is invalid due to its length, or sequence
2014-10-28 03:03:07 +00:00
// of characters. See validateLabelKey for more details.
2014-08-19 03:41:20 +00:00
//
// The empty string is a valid value in the input values set.
2015-09-09 17:45:01 +00:00
func NewRequirement ( key string , op Operator , vals sets . String ) ( * Requirement , error ) {
2014-10-28 03:03:07 +00:00
if err := validateLabelKey ( key ) ; err != nil {
return nil , err
}
2014-08-19 03:41:20 +00:00
switch op {
2015-02-14 23:07:30 +00:00
case InOperator , NotInOperator :
2014-08-19 03:41:20 +00:00
if len ( vals ) == 0 {
2015-02-25 16:19:10 +00:00
return nil , fmt . Errorf ( "for 'in', 'notin' operators, values set can't be empty" )
2014-08-19 03:41:20 +00:00
}
2015-02-14 23:07:30 +00:00
case EqualsOperator , DoubleEqualsOperator , NotEqualsOperator :
if len ( vals ) != 1 {
2015-10-12 23:13:41 +00:00
return nil , fmt . Errorf ( "exact-match compatibility requires one single value" )
}
case ExistsOperator , DoesNotExistOperator :
if len ( vals ) != 0 {
return nil , fmt . Errorf ( "values set must be empty for exists and does not exist" )
2015-02-14 23:07:30 +00:00
}
2016-01-26 23:03:18 +00:00
case GreaterThanOperator , LessThanOperator :
if len ( vals ) != 1 {
return nil , fmt . Errorf ( "for 'Gt', 'Lt' operators, exactly one value is required" )
}
for val := range vals {
if _ , err := strconv . ParseFloat ( val , 64 ) ; err != nil {
return nil , fmt . Errorf ( "for 'Gt', 'Lt' operators, the value must be a number" )
}
}
2014-08-19 03:41:20 +00:00
default :
return nil , fmt . Errorf ( "operator '%v' is not recognized" , op )
}
2015-02-14 23:07:30 +00:00
for v := range vals {
if err := validateLabelValue ( v ) ; err != nil {
return nil , err
}
}
2014-08-19 03:41:20 +00:00
return & Requirement { key : key , operator : op , strValues : vals } , nil
}
// Matches returns true if the Requirement matches the input Labels.
// There is a match in the following cases:
// (1) The operator is Exists and Labels has the Requirement's key.
// (2) The operator is In, Labels has the Requirement's key and Labels'
// value for that key is in Requirement's value set.
// (3) The operator is NotIn, Labels has the Requirement's key and
// Labels' value for that key is not in Requirement's value set.
2015-10-12 23:13:41 +00:00
// (4) The operator is DoesNotExist or NotIn and Labels does not have the
2014-08-19 03:41:20 +00:00
// Requirement's key.
2015-02-14 23:07:30 +00:00
func ( r * Requirement ) Matches ( ls Labels ) bool {
2014-08-01 03:56:37 +00:00
switch r . operator {
2015-02-14 23:07:30 +00:00
case InOperator , EqualsOperator , DoubleEqualsOperator :
2014-08-19 03:41:20 +00:00
if ! ls . Has ( r . key ) {
2015-02-14 23:07:30 +00:00
return false
2014-08-19 03:41:20 +00:00
}
2015-02-14 23:07:30 +00:00
return r . strValues . Has ( ls . Get ( r . key ) )
case NotInOperator , NotEqualsOperator :
2014-08-19 03:41:20 +00:00
if ! ls . Has ( r . key ) {
2015-02-14 23:07:30 +00:00
return true
2014-08-19 03:41:20 +00:00
}
2015-02-14 23:07:30 +00:00
return ! r . strValues . Has ( ls . Get ( r . key ) )
case ExistsOperator :
return ls . Has ( r . key )
2015-10-12 23:13:41 +00:00
case DoesNotExistOperator :
return ! ls . Has ( r . key )
2016-01-26 23:03:18 +00:00
case GreaterThanOperator , LessThanOperator :
if ! ls . Has ( r . key ) {
return false
}
lsValue , err := strconv . ParseFloat ( ls . Get ( r . key ) , 64 )
if err != nil {
glog . V ( 10 ) . Infof ( "Parse float failed for value %+v in label %+v, %+v" , ls . Get ( r . key ) , ls , err )
return false
}
// There should be only one strValue in r.strValues, and can be converted to a float number.
if len ( r . strValues ) != 1 {
glog . V ( 10 ) . Infof ( "Invalid values count %+v of requirement %+v, for 'Gt', 'Lt' operators, exactly one value is required" , len ( r . strValues ) , r )
return false
}
var rValue float64
for strValue := range r . strValues {
rValue , err = strconv . ParseFloat ( strValue , 64 )
if err != nil {
glog . V ( 10 ) . Infof ( "Parse float failed for value %+v in requirement %+v, for 'Gt', 'Lt' operators, the value must be a number" , strValue , r )
return false
}
}
return ( r . operator == GreaterThanOperator && lsValue > rValue ) || ( r . operator == LessThanOperator && lsValue < rValue )
2014-07-31 04:29:42 +00:00
default :
2015-02-14 23:07:30 +00:00
return false
}
}
2015-10-05 18:48:20 +00:00
func ( r * Requirement ) Key ( ) string {
return r . key
}
func ( r * Requirement ) Operator ( ) Operator {
return r . operator
}
func ( r * Requirement ) Values ( ) sets . String {
ret := sets . String { }
for k := range r . strValues {
ret . Insert ( k )
}
return ret
}
2015-12-03 08:04:55 +00:00
// Return true if the internalSelector doesn't restrict selection space
func ( lsel internalSelector ) Empty ( ) bool {
2015-03-22 17:03:50 +00:00
if lsel == nil {
2015-02-14 23:07:30 +00:00
return true
}
2015-03-22 17:03:50 +00:00
return len ( lsel ) == 0
2014-07-31 04:29:42 +00:00
}
2014-08-19 03:41:20 +00:00
// String returns a human-readable string that represents this
// Requirement. If called on an invalid Requirement, an error is
// returned. See NewRequirement for creating a valid Requirement.
2015-02-14 23:07:30 +00:00
func ( r * Requirement ) String ( ) string {
2014-08-19 03:41:20 +00:00
var buffer bytes . Buffer
2015-10-12 23:13:41 +00:00
if r . operator == DoesNotExistOperator {
buffer . WriteString ( "!" )
}
2014-08-19 03:41:20 +00:00
buffer . WriteString ( r . key )
switch r . operator {
2015-02-14 23:07:30 +00:00
case EqualsOperator :
buffer . WriteString ( "=" )
case DoubleEqualsOperator :
buffer . WriteString ( "==" )
case NotEqualsOperator :
buffer . WriteString ( "!=" )
case InOperator :
2014-08-19 03:41:20 +00:00
buffer . WriteString ( " in " )
2015-02-14 23:07:30 +00:00
case NotInOperator :
buffer . WriteString ( " notin " )
2016-01-26 23:03:18 +00:00
case GreaterThanOperator :
buffer . WriteString ( ">" )
case LessThanOperator :
buffer . WriteString ( "<" )
2015-10-12 23:13:41 +00:00
case ExistsOperator , DoesNotExistOperator :
2015-02-14 23:07:30 +00:00
return buffer . String ( )
2014-08-19 03:41:20 +00:00
}
2015-02-14 23:07:30 +00:00
switch r . operator {
case InOperator , NotInOperator :
buffer . WriteString ( "(" )
}
2014-08-19 03:41:20 +00:00
if len ( r . strValues ) == 1 {
buffer . WriteString ( r . strValues . List ( ) [ 0 ] )
} else { // only > 1 since == 0 prohibited by NewRequirement
buffer . WriteString ( strings . Join ( r . strValues . List ( ) , "," ) )
}
2015-02-14 23:07:30 +00:00
switch r . operator {
case InOperator , NotInOperator :
buffer . WriteString ( ")" )
}
return buffer . String ( )
2014-08-19 03:41:20 +00:00
}
2015-12-03 08:04:55 +00:00
// Add adds requirements to the selector. It copies the current selector returning a new one
func ( lsel internalSelector ) Add ( reqs ... Requirement ) Selector {
var sel internalSelector
2015-12-10 05:51:43 +00:00
for ix := range lsel {
sel = append ( sel , lsel [ ix ] )
2015-03-25 15:17:22 +00:00
}
2015-12-03 08:04:55 +00:00
for _ , r := range reqs {
sel = append ( sel , r )
2015-03-25 15:17:22 +00:00
}
2015-12-03 08:04:55 +00:00
sort . Sort ( ByKey ( sel ) )
return sel
2015-03-25 15:17:22 +00:00
}
2015-12-03 08:04:55 +00:00
// Matches for a internalSelector returns true if all
2014-08-19 03:41:20 +00:00
// its Requirements match the input Labels. If any
// Requirement does not match, false is returned.
2015-12-03 08:04:55 +00:00
func ( lsel internalSelector ) Matches ( l Labels ) bool {
2015-12-10 05:51:43 +00:00
for ix := range lsel {
if matches := lsel [ ix ] . Matches ( l ) ; ! matches {
2015-02-14 23:07:30 +00:00
return false
}
}
return true
}
2014-08-19 03:41:20 +00:00
// String returns a comma-separated string of all
2015-12-03 08:04:55 +00:00
// the internalSelector Requirements' human-readable strings.
func ( lsel internalSelector ) String ( ) string {
2014-08-19 03:41:20 +00:00
var reqs [ ] string
2015-12-10 05:51:43 +00:00
for ix := range lsel {
reqs = append ( reqs , lsel [ ix ] . String ( ) )
2015-02-14 23:07:30 +00:00
}
return strings . Join ( reqs , "," )
}
// constants definition for lexer token
type Token int
const (
2015-02-25 16:19:10 +00:00
ErrorToken Token = iota
EndOfStringToken
ClosedParToken
CommaToken
2015-10-12 23:13:41 +00:00
DoesNotExistToken
2015-02-25 16:19:10 +00:00
DoubleEqualsToken
EqualsToken
2016-01-26 23:03:18 +00:00
GreaterThanToken
2015-02-25 16:19:10 +00:00
IdentifierToken // to represent keys and values
InToken
2016-01-26 23:03:18 +00:00
LessThanToken
2015-02-25 16:19:10 +00:00
NotEqualsToken
NotInToken
OpenParToken
2015-02-14 23:07:30 +00:00
)
// string2token contains the mapping between lexer Token and token literal
2015-02-25 16:19:10 +00:00
// (except IdentifierToken, EndOfStringToken and ErrorToken since it makes no sense)
2015-02-14 23:07:30 +00:00
var string2token = map [ string ] Token {
2015-02-25 16:19:10 +00:00
")" : ClosedParToken ,
"," : CommaToken ,
2015-10-12 23:13:41 +00:00
"!" : DoesNotExistToken ,
2015-02-25 16:19:10 +00:00
"==" : DoubleEqualsToken ,
"=" : EqualsToken ,
2016-01-26 23:03:18 +00:00
">" : GreaterThanToken ,
2015-02-25 16:19:10 +00:00
"in" : InToken ,
2016-01-26 23:03:18 +00:00
"<" : LessThanToken ,
2015-02-25 16:19:10 +00:00
"!=" : NotEqualsToken ,
"notin" : NotInToken ,
"(" : OpenParToken ,
2015-02-14 23:07:30 +00:00
}
// The item produced by the lexer. It contains the Token and the literal.
type ScannedItem struct {
tok Token
literal string
}
// isWhitespace returns true if the rune is a space, tab, or newline.
func isWhitespace ( ch byte ) bool {
return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'
}
// isSpecialSymbol detect if the character ch can be an operator
func isSpecialSymbol ( ch byte ) bool {
switch ch {
2016-01-26 23:03:18 +00:00
case '=' , '!' , '(' , ')' , ',' , '>' , '<' :
2015-02-14 23:07:30 +00:00
return true
}
return false
}
2015-02-25 16:19:10 +00:00
// Lexer represents the Lexer struct for label selector.
// It contains necessary informationt to tokenize the input string
2015-02-14 23:07:30 +00:00
type Lexer struct {
2015-02-25 16:19:10 +00:00
// s stores the string to be tokenized
2015-02-14 23:07:30 +00:00
s string
2015-02-25 16:19:10 +00:00
// pos is the position currently tokenized
2015-02-14 23:07:30 +00:00
pos int
}
// read return the character currently lexed
// increment the position and check the buffer overflow
func ( l * Lexer ) read ( ) ( b byte ) {
b = 0
if l . pos < len ( l . s ) {
b = l . s [ l . pos ]
l . pos ++
}
return b
}
2015-02-25 16:19:10 +00:00
// unread 'undoes' the last read character
2015-02-14 23:07:30 +00:00
func ( l * Lexer ) unread ( ) {
l . pos --
}
2015-02-25 16:19:10 +00:00
// scanIdOrKeyword scans string to recognize literal token (for example 'in') or an identifier.
2015-02-14 23:07:30 +00:00
func ( l * Lexer ) scanIdOrKeyword ( ) ( tok Token , lit string ) {
var buffer [ ] byte
2015-02-25 16:19:10 +00:00
IdentifierLoop :
2015-02-14 23:07:30 +00:00
for {
2015-02-25 16:19:10 +00:00
switch ch := l . read ( ) ; {
case ch == 0 :
break IdentifierLoop
case isSpecialSymbol ( ch ) || isWhitespace ( ch ) :
l . unread ( )
break IdentifierLoop
default :
2015-02-14 23:07:30 +00:00
buffer = append ( buffer , ch )
}
}
s := string ( buffer )
if val , ok := string2token [ s ] ; ok { // is a literal token?
return val , s
}
2015-02-25 16:19:10 +00:00
return IdentifierToken , s // otherwise is an identifier
2015-02-14 23:07:30 +00:00
}
2015-02-25 16:19:10 +00:00
// scanSpecialSymbol scans string starting with special symbol.
// special symbol identify non literal operators. "!=", "==", "="
2015-02-14 23:07:30 +00:00
func ( l * Lexer ) scanSpecialSymbol ( ) ( Token , string ) {
lastScannedItem := ScannedItem { }
var buffer [ ] byte
2015-02-25 16:19:10 +00:00
SpecialSymbolLoop :
2015-02-14 23:07:30 +00:00
for {
2015-02-25 16:19:10 +00:00
switch ch := l . read ( ) ; {
case ch == 0 :
break SpecialSymbolLoop
case isSpecialSymbol ( ch ) :
2015-02-14 23:07:30 +00:00
buffer = append ( buffer , ch )
if token , ok := string2token [ string ( buffer ) ] ; ok {
lastScannedItem = ScannedItem { tok : token , literal : string ( buffer ) }
} else if lastScannedItem . tok != 0 {
l . unread ( )
2015-02-25 16:19:10 +00:00
break SpecialSymbolLoop
2015-02-14 23:07:30 +00:00
}
2015-02-25 16:19:10 +00:00
default :
2015-02-14 23:07:30 +00:00
l . unread ( )
2015-02-25 16:19:10 +00:00
break SpecialSymbolLoop
2015-02-14 23:07:30 +00:00
}
}
if lastScannedItem . tok == 0 {
2015-02-25 16:19:10 +00:00
return ErrorToken , fmt . Sprintf ( "error expected: keyword found '%s'" , buffer )
2015-02-14 23:07:30 +00:00
}
2015-02-25 16:19:10 +00:00
return lastScannedItem . tok , lastScannedItem . literal
2015-02-14 23:07:30 +00:00
}
2015-02-25 16:19:10 +00:00
// skipWhiteSpaces consumes all blank characters
// returning the first non blank character
func ( l * Lexer ) skipWhiteSpaces ( ch byte ) byte {
for {
2015-02-14 23:07:30 +00:00
if ! isWhitespace ( ch ) {
2015-02-25 16:19:10 +00:00
return ch
2015-02-14 23:07:30 +00:00
}
ch = l . read ( )
}
2015-02-25 16:19:10 +00:00
}
// Lex returns a pair of Token and the literal
// literal is meaningfull only for IdentifierToken token
func ( l * Lexer ) Lex ( ) ( tok Token , lit string ) {
switch ch := l . skipWhiteSpaces ( l . read ( ) ) ; {
case ch == 0 :
return EndOfStringToken , ""
case isSpecialSymbol ( ch ) :
2015-02-14 23:07:30 +00:00
l . unread ( )
2015-02-25 16:19:10 +00:00
return l . scanSpecialSymbol ( )
default :
2015-02-14 23:07:30 +00:00
l . unread ( )
return l . scanIdOrKeyword ( )
}
}
2015-02-25 16:19:10 +00:00
// Parser data structure contains the label selector parser data strucutre
2015-02-14 23:07:30 +00:00
type Parser struct {
l * Lexer
scannedItems [ ] ScannedItem
position int
}
2015-02-25 16:19:10 +00:00
// Parser context represents context during parsing:
// some literal for example 'in' and 'notin' can be
// recognized as operator for example 'x in (a)' but
// it can be recognized as value for example 'value in (in)'
2015-02-14 23:07:30 +00:00
type ParserContext int
const (
KeyAndOperator ParserContext = iota
Values
)
// lookahead func returns the current token and string. No increment of current position
func ( p * Parser ) lookahead ( context ParserContext ) ( Token , string ) {
tok , lit := p . scannedItems [ p . position ] . tok , p . scannedItems [ p . position ] . literal
if context == Values {
switch tok {
2015-02-25 16:19:10 +00:00
case InToken , NotInToken :
tok = IdentifierToken
2015-02-14 23:07:30 +00:00
}
}
return tok , lit
}
2015-02-25 16:19:10 +00:00
// consume returns current token and string. Increments the the position
2015-02-14 23:07:30 +00:00
func ( p * Parser ) consume ( context ParserContext ) ( Token , string ) {
p . position ++
tok , lit := p . scannedItems [ p . position - 1 ] . tok , p . scannedItems [ p . position - 1 ] . literal
if context == Values {
switch tok {
2015-02-25 16:19:10 +00:00
case InToken , NotInToken :
tok = IdentifierToken
2015-02-14 23:07:30 +00:00
}
}
return tok , lit
}
2015-02-25 16:19:10 +00:00
// scan runs through the input string and stores the ScannedItem in an array
// Parser can now lookahead and consume the tokens
2015-02-14 23:07:30 +00:00
func ( p * Parser ) scan ( ) {
for {
token , literal := p . l . Lex ( )
p . scannedItems = append ( p . scannedItems , ScannedItem { token , literal } )
2015-02-25 16:19:10 +00:00
if token == EndOfStringToken {
2015-02-14 23:07:30 +00:00
break
}
}
}
2015-02-25 16:19:10 +00:00
// parse runs the left recursive descending algorithm
// on input string. It returns a list of Requirement objects.
2015-12-03 08:04:55 +00:00
func ( p * Parser ) parse ( ) ( internalSelector , error ) {
2015-02-14 23:07:30 +00:00
p . scan ( ) // init scannedItems
2015-12-03 08:04:55 +00:00
var requirements internalSelector
2015-02-14 23:07:30 +00:00
for {
tok , lit := p . lookahead ( Values )
switch tok {
2015-10-12 23:13:41 +00:00
case IdentifierToken , DoesNotExistToken :
2015-02-14 23:07:30 +00:00
r , err := p . parseRequirement ( )
if err != nil {
2015-09-02 23:52:22 +00:00
return nil , fmt . Errorf ( "unable to parse requirement: %v" , err )
2015-02-14 23:07:30 +00:00
}
requirements = append ( requirements , * r )
t , l := p . consume ( Values )
switch t {
2015-02-25 16:19:10 +00:00
case EndOfStringToken :
2015-02-14 23:07:30 +00:00
return requirements , nil
2015-02-25 16:19:10 +00:00
case CommaToken :
2015-02-14 23:07:30 +00:00
t2 , l2 := p . lookahead ( Values )
2015-10-12 23:13:41 +00:00
if t2 != IdentifierToken && t2 != DoesNotExistToken {
2015-02-25 16:19:10 +00:00
return nil , fmt . Errorf ( "found '%s', expected: identifier after ','" , l2 )
2015-02-14 23:07:30 +00:00
}
default :
2015-02-25 16:19:10 +00:00
return nil , fmt . Errorf ( "found '%s', expected: ',' or 'end of string'" , l )
2015-02-14 23:07:30 +00:00
}
2015-02-25 16:19:10 +00:00
case EndOfStringToken :
2015-02-14 23:07:30 +00:00
return requirements , nil
default :
2015-10-12 23:13:41 +00:00
return nil , fmt . Errorf ( "found '%s', expected: !, identifier, or 'end of string'" , lit )
2015-02-14 23:07:30 +00:00
}
}
}
func ( p * Parser ) parseRequirement ( ) ( * Requirement , error ) {
key , operator , err := p . parseKeyAndInferOperator ( )
if err != nil {
return nil , err
}
2015-10-12 23:13:41 +00:00
if operator == ExistsOperator || operator == DoesNotExistOperator { // operator found lookahead set checked
2015-02-14 23:07:30 +00:00
return NewRequirement ( key , operator , nil )
}
operator , err = p . parseOperator ( )
if err != nil {
return nil , err
}
2015-09-09 17:45:01 +00:00
var values sets . String
2015-02-14 23:07:30 +00:00
switch operator {
case InOperator , NotInOperator :
values , err = p . parseValues ( )
2016-01-26 23:03:18 +00:00
case EqualsOperator , DoubleEqualsOperator , NotEqualsOperator , GreaterThanOperator , LessThanOperator :
2015-02-14 23:07:30 +00:00
values , err = p . parseExactValue ( )
}
if err != nil {
return nil , err
}
return NewRequirement ( key , operator , values )
}
// parseKeyAndInferOperator parse literals.
2015-10-12 23:13:41 +00:00
// in case of no operator '!, in, notin, ==, =, !=' are found
// the 'exists' operator is inferred
2015-02-14 23:07:30 +00:00
func ( p * Parser ) parseKeyAndInferOperator ( ) ( string , Operator , error ) {
2015-10-12 23:13:41 +00:00
var operator Operator
2015-02-14 23:07:30 +00:00
tok , literal := p . consume ( Values )
2015-10-12 23:13:41 +00:00
if tok == DoesNotExistToken {
operator = DoesNotExistOperator
tok , literal = p . consume ( Values )
}
2015-02-25 16:19:10 +00:00
if tok != IdentifierToken {
err := fmt . Errorf ( "found '%s', expected: identifier" , literal )
2015-02-14 23:07:30 +00:00
return "" , "" , err
}
if err := validateLabelKey ( literal ) ; err != nil {
return "" , "" , err
}
2015-02-25 16:19:10 +00:00
if t , _ := p . lookahead ( Values ) ; t == EndOfStringToken || t == CommaToken {
2015-10-12 23:13:41 +00:00
if operator != DoesNotExistOperator {
operator = ExistsOperator
}
2015-02-14 23:07:30 +00:00
}
return literal , operator , nil
}
// parseOperator return operator and eventually matchType
// matchType can be exact
func ( p * Parser ) parseOperator ( ) ( op Operator , err error ) {
tok , lit := p . consume ( KeyAndOperator )
switch tok {
2015-10-12 23:13:41 +00:00
// DoesNotExistToken shouldn't be here because it's a unary operator, not a binary operator
2015-02-25 16:19:10 +00:00
case InToken :
2015-02-14 23:07:30 +00:00
op = InOperator
2015-02-25 16:19:10 +00:00
case EqualsToken :
2015-02-14 23:07:30 +00:00
op = EqualsOperator
2015-02-25 16:19:10 +00:00
case DoubleEqualsToken :
2015-02-14 23:07:30 +00:00
op = DoubleEqualsOperator
2016-01-26 23:03:18 +00:00
case GreaterThanToken :
op = GreaterThanOperator
case LessThanToken :
op = LessThanOperator
2015-02-25 16:19:10 +00:00
case NotInToken :
2015-02-14 23:07:30 +00:00
op = NotInOperator
2015-02-25 16:19:10 +00:00
case NotEqualsToken :
2015-02-14 23:07:30 +00:00
op = NotEqualsOperator
default :
2015-02-25 16:19:10 +00:00
return "" , fmt . Errorf ( "found '%s', expected: '=', '!=', '==', 'in', notin'" , lit )
2015-02-14 23:07:30 +00:00
}
return op , nil
}
2015-02-25 16:19:10 +00:00
// parseValues parses the values for set based matching (x,y,z)
2015-09-09 17:45:01 +00:00
func ( p * Parser ) parseValues ( ) ( sets . String , error ) {
2015-02-14 23:07:30 +00:00
tok , lit := p . consume ( Values )
2015-02-25 16:19:10 +00:00
if tok != OpenParToken {
return nil , fmt . Errorf ( "found '%s' expected: '('" , lit )
2015-02-14 23:07:30 +00:00
}
tok , lit = p . lookahead ( Values )
switch tok {
2015-02-25 16:19:10 +00:00
case IdentifierToken , CommaToken :
2015-02-14 23:07:30 +00:00
s , err := p . parseIdentifiersList ( ) // handles general cases
if err != nil {
return s , err
}
2015-02-25 16:19:10 +00:00
if tok , _ = p . consume ( Values ) ; tok != ClosedParToken {
return nil , fmt . Errorf ( "found '%s', expected: ')'" , lit )
2015-02-14 23:07:30 +00:00
}
return s , nil
2015-02-25 16:19:10 +00:00
case ClosedParToken : // handles "()"
2015-02-14 23:07:30 +00:00
p . consume ( Values )
2015-09-09 17:45:01 +00:00
return sets . NewString ( "" ) , nil
2015-02-14 23:07:30 +00:00
default :
2015-02-25 16:19:10 +00:00
return nil , fmt . Errorf ( "found '%s', expected: ',', ')' or identifier" , lit )
2015-02-14 23:07:30 +00:00
}
}
2015-02-25 16:19:10 +00:00
// parseIdentifiersList parses a (possibly empty) list of
2015-02-14 23:07:30 +00:00
// of comma separated (possibly empty) identifiers
2015-09-09 17:45:01 +00:00
func ( p * Parser ) parseIdentifiersList ( ) ( sets . String , error ) {
s := sets . NewString ( )
2015-02-14 23:07:30 +00:00
for {
tok , lit := p . consume ( Values )
switch tok {
2015-02-25 16:19:10 +00:00
case IdentifierToken :
2015-02-14 23:07:30 +00:00
s . Insert ( lit )
tok2 , lit2 := p . lookahead ( Values )
switch tok2 {
2015-02-25 16:19:10 +00:00
case CommaToken :
2015-02-14 23:07:30 +00:00
continue
2015-02-25 16:19:10 +00:00
case ClosedParToken :
2015-02-14 23:07:30 +00:00
return s , nil
default :
2015-02-25 16:19:10 +00:00
return nil , fmt . Errorf ( "found '%s', expected: ',' or ')'" , lit2 )
2015-02-14 23:07:30 +00:00
}
2015-02-25 16:19:10 +00:00
case CommaToken : // handled here since we can have "(,"
2015-02-14 23:07:30 +00:00
if s . Len ( ) == 0 {
s . Insert ( "" ) // to handle (,
}
tok2 , _ := p . lookahead ( Values )
2015-02-25 16:19:10 +00:00
if tok2 == ClosedParToken {
2015-02-14 23:07:30 +00:00
s . Insert ( "" ) // to handle ,) Double "" removed by StringSet
return s , nil
}
2015-02-25 16:19:10 +00:00
if tok2 == CommaToken {
2015-02-14 23:07:30 +00:00
p . consume ( Values )
s . Insert ( "" ) // to handle ,, Double "" removed by StringSet
}
default : // it can be operator
2015-02-25 16:19:10 +00:00
return s , fmt . Errorf ( "found '%s', expected: ',', or identifier" , lit )
2014-08-19 03:41:20 +00:00
}
}
2015-02-14 23:07:30 +00:00
}
2015-02-25 16:19:10 +00:00
// parseExactValue parses the only value for exact match style
2015-09-09 17:45:01 +00:00
func ( p * Parser ) parseExactValue ( ) ( sets . String , error ) {
s := sets . NewString ( )
2015-10-02 22:06:58 +00:00
tok , lit := p . lookahead ( Values )
if tok == EndOfStringToken || tok == CommaToken {
s . Insert ( "" )
return s , nil
}
tok , lit = p . consume ( Values )
2015-02-25 16:19:10 +00:00
if tok == IdentifierToken {
2015-02-14 23:07:30 +00:00
s . Insert ( lit )
2015-02-25 16:19:10 +00:00
return s , nil
2015-02-14 23:07:30 +00:00
}
2015-02-25 16:19:10 +00:00
return nil , fmt . Errorf ( "found '%s', expected: identifier" , lit )
2014-08-19 03:41:20 +00:00
}
2014-10-28 03:03:07 +00:00
// Parse takes a string representing a selector and returns a selector
// object, or an error. This parsing function differs from ParseSelector
// as they parse different selectors with different syntaxes.
// The input will cause an error if it does not follow this form:
//
2015-02-14 23:07:30 +00:00
// <selector-syntax> ::= <requirement> | <requirement> "," <selector-syntax> ]
2015-10-12 23:13:41 +00:00
// <requirement> ::= [!] KEY [ <set-based-restriction> | <exact-match-restriction> ]
2015-02-14 23:07:30 +00:00
// <set-based-restriction> ::= "" | <inclusion-exclusion> <value-set>
2014-11-24 02:55:34 +00:00
// <inclusion-exclusion> ::= <inclusion> | <exclusion>
2015-07-03 15:33:46 +00:00
// <exclusion> ::= "notin"
2015-02-14 23:07:30 +00:00
// <inclusion> ::= "in"
2014-10-28 03:03:07 +00:00
// <value-set> ::= "(" <values> ")"
// <values> ::= VALUE | VALUE "," <values>
2015-02-14 23:07:30 +00:00
// <exact-match-restriction> ::= ["="|"=="|"!="] VALUE
2015-12-09 08:45:31 +00:00
// KEY is a sequence of one or more characters following [ DNS_SUBDOMAIN "/" ] DNS_LABEL. Max length is 63 characters.
// VALUE is a sequence of zero or more characters "([A-Za-z0-9_-\.])". Max length is 63 characters.
2015-02-14 23:07:30 +00:00
// Delimiter is white space: (' ', '\t')
2014-10-28 03:03:07 +00:00
// Example of valid syntax:
2015-07-03 15:33:46 +00:00
// "x in (foo,,baz),y,z notin ()"
2014-10-28 03:03:07 +00:00
//
// Note:
2015-10-12 23:13:41 +00:00
// (1) Inclusion - " in " - denotes that the KEY exists and is equal to any of the
2014-10-28 03:03:07 +00:00
// VALUEs in its requirement
2015-07-03 15:33:46 +00:00
// (2) Exclusion - " notin " - denotes that the KEY is not equal to any
2015-10-12 23:13:41 +00:00
// of the VALUEs in its requirement or does not exist
2014-10-28 03:03:07 +00:00
// (3) The empty string is a valid VALUE
// (4) A requirement with just a KEY - as in "y" above - denotes that
// the KEY exists and can be any VALUE.
2015-10-12 23:13:41 +00:00
// (5) A requirement with just !KEY requires that the KEY not exist.
2014-10-28 03:03:07 +00:00
//
2015-02-14 23:07:30 +00:00
func Parse ( selector string ) ( Selector , error ) {
p := & Parser { l : & Lexer { s : selector , pos : 0 } }
items , error := p . parse ( )
if error == nil {
sort . Sort ( ByKey ( items ) ) // sort to grant determistic parsing
2015-12-03 08:04:55 +00:00
return internalSelector ( items ) , error
2014-10-28 03:03:07 +00:00
}
2015-02-14 23:07:30 +00:00
return nil , error
}
2014-10-28 03:03:07 +00:00
2015-12-09 08:45:31 +00:00
var qualifiedNameErrorMsg string = fmt . Sprintf ( ` must be a qualified name (at most %d characters, matching regex %s), with an optional DNS subdomain prefix (at most %d characters, matching regex %s) and slash (/): e.g. "MyName" or "example.com/MyName" ` , validation . QualifiedNameMaxLength , validation . QualifiedNameFmt , validation . DNS1123SubdomainMaxLength , validation . DNS1123SubdomainFmt )
var labelValueErrorMsg string = fmt . Sprintf ( ` must have at most %d characters, matching regex %s: e.g. "MyValue" or "" ` , validation . LabelValueMaxLength , validation . LabelValueFmt )
2014-10-28 03:03:07 +00:00
2015-02-14 23:07:30 +00:00
func validateLabelKey ( k string ) error {
2015-09-10 22:48:28 +00:00
if ! validation . IsQualifiedName ( k ) {
2015-11-04 21:52:14 +00:00
return fmt . Errorf ( "invalid label key: %s" , qualifiedNameErrorMsg )
2015-02-14 23:07:30 +00:00
}
return nil
2014-10-28 03:03:07 +00:00
}
2015-02-14 23:07:30 +00:00
func validateLabelValue ( v string ) error {
2015-09-10 22:48:28 +00:00
if ! validation . IsValidLabelValue ( v ) {
2015-12-09 08:45:31 +00:00
return fmt . Errorf ( "invalid label value: %s" , labelValueErrorMsg )
2014-10-28 03:03:07 +00:00
}
return nil
}
2014-08-19 03:41:20 +00:00
2014-07-25 16:15:17 +00:00
// SelectorFromSet returns a Selector which will match exactly the given Set. A
2015-04-21 20:40:35 +00:00
// nil and empty Sets are considered equivalent to Everything().
2014-06-18 23:47:41 +00:00
func SelectorFromSet ( ls Set ) Selector {
2014-07-25 16:15:17 +00:00
if ls == nil {
2015-12-03 08:04:55 +00:00
return internalSelector { }
2015-02-14 23:07:30 +00:00
}
2015-12-03 08:04:55 +00:00
var requirements internalSelector
2015-02-14 23:07:30 +00:00
for label , value := range ls {
2015-09-09 17:45:01 +00:00
if r , err := NewRequirement ( label , EqualsOperator , sets . NewString ( value ) ) ; err != nil {
2015-03-22 17:03:50 +00:00
//TODO: double check errors when input comes from serialization?
2015-12-03 08:04:55 +00:00
return internalSelector { }
2015-02-14 23:07:30 +00:00
} else {
requirements = append ( requirements , * r )
}
}
2015-11-13 13:38:38 +00:00
// sort to have deterministic string representation
sort . Sort ( ByKey ( requirements ) )
2015-12-03 08:04:55 +00:00
return internalSelector ( requirements )
2015-02-14 23:07:30 +00:00
}