github.com/timstclair/heapster@v0.20.0-alpha1/Godeps/_workspace/src/k8s.io/kubernetes/pkg/labels/selector.go (about) 1 /* 2 Copyright 2014 The Kubernetes Authors All rights reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package labels 18 19 import ( 20 "bytes" 21 "fmt" 22 "sort" 23 "strings" 24 25 "k8s.io/kubernetes/pkg/util/sets" 26 "k8s.io/kubernetes/pkg/util/validation" 27 ) 28 29 // Selector represents a label selector. 30 type Selector interface { 31 // Matches returns true if this selector matches the given set of labels. 32 Matches(Labels) bool 33 34 // Empty returns true if this selector does not restrict the selection space. 35 Empty() bool 36 37 // String returns a human readable string that represents this selector. 38 String() string 39 40 // Add add a specific requirement for the selector 41 Add(key string, operator Operator, values []string) Selector 42 } 43 44 // Everything returns a selector that matches all labels. 45 func Everything() Selector { 46 return LabelSelector{} 47 } 48 49 type nothingSelector struct{} 50 51 func (n nothingSelector) Matches(_ Labels) bool { return false } 52 func (n nothingSelector) Empty() bool { return false } 53 func (n nothingSelector) String() string { return "<null>" } 54 func (n nothingSelector) Add(_ string, _ Operator, _ []string) Selector { return n } 55 56 // Nothing returns a selector that matches no labels 57 func Nothing() Selector { 58 return nothingSelector{} 59 } 60 61 // Operator represents a key's relationship 62 // to a set of values in a Requirement. 63 type Operator string 64 65 const ( 66 DoesNotExistOperator Operator = "!" 67 EqualsOperator Operator = "=" 68 DoubleEqualsOperator Operator = "==" 69 InOperator Operator = "in" 70 NotEqualsOperator Operator = "!=" 71 NotInOperator Operator = "notin" 72 ExistsOperator Operator = "exists" 73 ) 74 75 //LabelSelector is a list of Requirements. 76 type LabelSelector []Requirement 77 78 // Sort by obtain determisitic parser 79 type ByKey []Requirement 80 81 func (a ByKey) Len() int { return len(a) } 82 83 func (a ByKey) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 84 85 func (a ByKey) Less(i, j int) bool { return a[i].key < a[j].key } 86 87 // Requirement is a selector that contains values, a key 88 // and an operator that relates the key and values. The zero 89 // value of Requirement is invalid. 90 // Requirement implements both set based match and exact match 91 // Requirement is initialized via NewRequirement constructor for creating a valid Requirement. 92 type Requirement struct { 93 key string 94 operator Operator 95 strValues sets.String 96 } 97 98 // NewRequirement is the constructor for a Requirement. 99 // If any of these rules is violated, an error is returned: 100 // (1) The operator can only be In, NotIn, Equals, DoubleEquals, NotEquals, Exists, or DoesNotExist. 101 // (2) If the operator is In or NotIn, the values set must be non-empty. 102 // (3) If the operator is Equals, DoubleEquals, or NotEquals, the values set must contain one value. 103 // (4) If the operator is Exists or DoesNotExist, the value set must be empty. 104 // (5) The key is invalid due to its length, or sequence 105 // of characters. See validateLabelKey for more details. 106 // 107 // The empty string is a valid value in the input values set. 108 func NewRequirement(key string, op Operator, vals sets.String) (*Requirement, error) { 109 if err := validateLabelKey(key); err != nil { 110 return nil, err 111 } 112 switch op { 113 case InOperator, NotInOperator: 114 if len(vals) == 0 { 115 return nil, fmt.Errorf("for 'in', 'notin' operators, values set can't be empty") 116 } 117 case EqualsOperator, DoubleEqualsOperator, NotEqualsOperator: 118 if len(vals) != 1 { 119 return nil, fmt.Errorf("exact-match compatibility requires one single value") 120 } 121 case ExistsOperator, DoesNotExistOperator: 122 if len(vals) != 0 { 123 return nil, fmt.Errorf("values set must be empty for exists and does not exist") 124 } 125 default: 126 return nil, fmt.Errorf("operator '%v' is not recognized", op) 127 } 128 129 for v := range vals { 130 if err := validateLabelValue(v); err != nil { 131 return nil, err 132 } 133 } 134 return &Requirement{key: key, operator: op, strValues: vals}, nil 135 } 136 137 // Matches returns true if the Requirement matches the input Labels. 138 // There is a match in the following cases: 139 // (1) The operator is Exists and Labels has the Requirement's key. 140 // (2) The operator is In, Labels has the Requirement's key and Labels' 141 // value for that key is in Requirement's value set. 142 // (3) The operator is NotIn, Labels has the Requirement's key and 143 // Labels' value for that key is not in Requirement's value set. 144 // (4) The operator is DoesNotExist or NotIn and Labels does not have the 145 // Requirement's key. 146 func (r *Requirement) Matches(ls Labels) bool { 147 switch r.operator { 148 case InOperator, EqualsOperator, DoubleEqualsOperator: 149 if !ls.Has(r.key) { 150 return false 151 } 152 return r.strValues.Has(ls.Get(r.key)) 153 case NotInOperator, NotEqualsOperator: 154 if !ls.Has(r.key) { 155 return true 156 } 157 return !r.strValues.Has(ls.Get(r.key)) 158 case ExistsOperator: 159 return ls.Has(r.key) 160 case DoesNotExistOperator: 161 return !ls.Has(r.key) 162 default: 163 return false 164 } 165 } 166 167 func (r *Requirement) Key() string { 168 return r.key 169 } 170 func (r *Requirement) Operator() Operator { 171 return r.operator 172 } 173 func (r *Requirement) Values() sets.String { 174 ret := sets.String{} 175 for k := range r.strValues { 176 ret.Insert(k) 177 } 178 return ret 179 } 180 181 // Return true if the LabelSelector doesn't restrict selection space 182 func (lsel LabelSelector) Empty() bool { 183 if lsel == nil { 184 return true 185 } 186 return len(lsel) == 0 187 } 188 189 // String returns a human-readable string that represents this 190 // Requirement. If called on an invalid Requirement, an error is 191 // returned. See NewRequirement for creating a valid Requirement. 192 func (r *Requirement) String() string { 193 var buffer bytes.Buffer 194 if r.operator == DoesNotExistOperator { 195 buffer.WriteString("!") 196 } 197 buffer.WriteString(r.key) 198 199 switch r.operator { 200 case EqualsOperator: 201 buffer.WriteString("=") 202 case DoubleEqualsOperator: 203 buffer.WriteString("==") 204 case NotEqualsOperator: 205 buffer.WriteString("!=") 206 case InOperator: 207 buffer.WriteString(" in ") 208 case NotInOperator: 209 buffer.WriteString(" notin ") 210 case ExistsOperator, DoesNotExistOperator: 211 return buffer.String() 212 } 213 214 switch r.operator { 215 case InOperator, NotInOperator: 216 buffer.WriteString("(") 217 } 218 if len(r.strValues) == 1 { 219 buffer.WriteString(r.strValues.List()[0]) 220 } else { // only > 1 since == 0 prohibited by NewRequirement 221 buffer.WriteString(strings.Join(r.strValues.List(), ",")) 222 } 223 224 switch r.operator { 225 case InOperator, NotInOperator: 226 buffer.WriteString(")") 227 } 228 return buffer.String() 229 } 230 231 // Add adds a requirement to the selector. It copies the current selector returning a new one 232 func (lsel LabelSelector) Add(key string, operator Operator, values []string) Selector { 233 var reqs []Requirement 234 for _, item := range lsel { 235 reqs = append(reqs, item) 236 } 237 if r, err := NewRequirement(key, operator, sets.NewString(values...)); err == nil { 238 reqs = append(reqs, *r) 239 } 240 return LabelSelector(reqs) 241 } 242 243 // Matches for a LabelSelector returns true if all 244 // its Requirements match the input Labels. If any 245 // Requirement does not match, false is returned. 246 func (lsel LabelSelector) Matches(l Labels) bool { 247 for _, req := range lsel { 248 if matches := req.Matches(l); !matches { 249 return false 250 } 251 } 252 return true 253 } 254 255 // String returns a comma-separated string of all 256 // the LabelSelector Requirements' human-readable strings. 257 func (lsel LabelSelector) String() string { 258 var reqs []string 259 for _, req := range lsel { 260 reqs = append(reqs, req.String()) 261 } 262 return strings.Join(reqs, ",") 263 } 264 265 // constants definition for lexer token 266 type Token int 267 268 const ( 269 ErrorToken Token = iota 270 EndOfStringToken 271 ClosedParToken 272 CommaToken 273 DoesNotExistToken 274 DoubleEqualsToken 275 EqualsToken 276 IdentifierToken // to represent keys and values 277 InToken 278 NotEqualsToken 279 NotInToken 280 OpenParToken 281 ) 282 283 // string2token contains the mapping between lexer Token and token literal 284 // (except IdentifierToken, EndOfStringToken and ErrorToken since it makes no sense) 285 var string2token = map[string]Token{ 286 ")": ClosedParToken, 287 ",": CommaToken, 288 "!": DoesNotExistToken, 289 "==": DoubleEqualsToken, 290 "=": EqualsToken, 291 "in": InToken, 292 "!=": NotEqualsToken, 293 "notin": NotInToken, 294 "(": OpenParToken, 295 } 296 297 // The item produced by the lexer. It contains the Token and the literal. 298 type ScannedItem struct { 299 tok Token 300 literal string 301 } 302 303 // isWhitespace returns true if the rune is a space, tab, or newline. 304 func isWhitespace(ch byte) bool { 305 return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' 306 } 307 308 // isSpecialSymbol detect if the character ch can be an operator 309 func isSpecialSymbol(ch byte) bool { 310 switch ch { 311 case '=', '!', '(', ')', ',': 312 return true 313 } 314 return false 315 } 316 317 // Lexer represents the Lexer struct for label selector. 318 // It contains necessary informationt to tokenize the input string 319 type Lexer struct { 320 // s stores the string to be tokenized 321 s string 322 // pos is the position currently tokenized 323 pos int 324 } 325 326 // read return the character currently lexed 327 // increment the position and check the buffer overflow 328 func (l *Lexer) read() (b byte) { 329 b = 0 330 if l.pos < len(l.s) { 331 b = l.s[l.pos] 332 l.pos++ 333 } 334 return b 335 } 336 337 // unread 'undoes' the last read character 338 func (l *Lexer) unread() { 339 l.pos-- 340 } 341 342 // scanIdOrKeyword scans string to recognize literal token (for example 'in') or an identifier. 343 func (l *Lexer) scanIdOrKeyword() (tok Token, lit string) { 344 var buffer []byte 345 IdentifierLoop: 346 for { 347 switch ch := l.read(); { 348 case ch == 0: 349 break IdentifierLoop 350 case isSpecialSymbol(ch) || isWhitespace(ch): 351 l.unread() 352 break IdentifierLoop 353 default: 354 buffer = append(buffer, ch) 355 } 356 } 357 s := string(buffer) 358 if val, ok := string2token[s]; ok { // is a literal token? 359 return val, s 360 } 361 return IdentifierToken, s // otherwise is an identifier 362 } 363 364 // scanSpecialSymbol scans string starting with special symbol. 365 // special symbol identify non literal operators. "!=", "==", "=" 366 func (l *Lexer) scanSpecialSymbol() (Token, string) { 367 lastScannedItem := ScannedItem{} 368 var buffer []byte 369 SpecialSymbolLoop: 370 for { 371 switch ch := l.read(); { 372 case ch == 0: 373 break SpecialSymbolLoop 374 case isSpecialSymbol(ch): 375 buffer = append(buffer, ch) 376 if token, ok := string2token[string(buffer)]; ok { 377 lastScannedItem = ScannedItem{tok: token, literal: string(buffer)} 378 } else if lastScannedItem.tok != 0 { 379 l.unread() 380 break SpecialSymbolLoop 381 } 382 default: 383 l.unread() 384 break SpecialSymbolLoop 385 } 386 } 387 if lastScannedItem.tok == 0 { 388 return ErrorToken, fmt.Sprintf("error expected: keyword found '%s'", buffer) 389 } 390 return lastScannedItem.tok, lastScannedItem.literal 391 } 392 393 // skipWhiteSpaces consumes all blank characters 394 // returning the first non blank character 395 func (l *Lexer) skipWhiteSpaces(ch byte) byte { 396 for { 397 if !isWhitespace(ch) { 398 return ch 399 } 400 ch = l.read() 401 } 402 } 403 404 // Lex returns a pair of Token and the literal 405 // literal is meaningfull only for IdentifierToken token 406 func (l *Lexer) Lex() (tok Token, lit string) { 407 switch ch := l.skipWhiteSpaces(l.read()); { 408 case ch == 0: 409 return EndOfStringToken, "" 410 case isSpecialSymbol(ch): 411 l.unread() 412 return l.scanSpecialSymbol() 413 default: 414 l.unread() 415 return l.scanIdOrKeyword() 416 } 417 } 418 419 // Parser data structure contains the label selector parser data strucutre 420 type Parser struct { 421 l *Lexer 422 scannedItems []ScannedItem 423 position int 424 } 425 426 // Parser context represents context during parsing: 427 // some literal for example 'in' and 'notin' can be 428 // recognized as operator for example 'x in (a)' but 429 // it can be recognized as value for example 'value in (in)' 430 type ParserContext int 431 432 const ( 433 KeyAndOperator ParserContext = iota 434 Values 435 ) 436 437 // lookahead func returns the current token and string. No increment of current position 438 func (p *Parser) lookahead(context ParserContext) (Token, string) { 439 tok, lit := p.scannedItems[p.position].tok, p.scannedItems[p.position].literal 440 if context == Values { 441 switch tok { 442 case InToken, NotInToken: 443 tok = IdentifierToken 444 } 445 } 446 return tok, lit 447 } 448 449 // consume returns current token and string. Increments the the position 450 func (p *Parser) consume(context ParserContext) (Token, string) { 451 p.position++ 452 tok, lit := p.scannedItems[p.position-1].tok, p.scannedItems[p.position-1].literal 453 if context == Values { 454 switch tok { 455 case InToken, NotInToken: 456 tok = IdentifierToken 457 } 458 } 459 return tok, lit 460 } 461 462 // scan runs through the input string and stores the ScannedItem in an array 463 // Parser can now lookahead and consume the tokens 464 func (p *Parser) scan() { 465 for { 466 token, literal := p.l.Lex() 467 p.scannedItems = append(p.scannedItems, ScannedItem{token, literal}) 468 if token == EndOfStringToken { 469 break 470 } 471 } 472 } 473 474 // parse runs the left recursive descending algorithm 475 // on input string. It returns a list of Requirement objects. 476 func (p *Parser) parse() ([]Requirement, error) { 477 p.scan() // init scannedItems 478 479 var requirements []Requirement 480 for { 481 tok, lit := p.lookahead(Values) 482 switch tok { 483 case IdentifierToken, DoesNotExistToken: 484 r, err := p.parseRequirement() 485 if err != nil { 486 return nil, fmt.Errorf("unable to parse requirement: %v", err) 487 } 488 requirements = append(requirements, *r) 489 t, l := p.consume(Values) 490 switch t { 491 case EndOfStringToken: 492 return requirements, nil 493 case CommaToken: 494 t2, l2 := p.lookahead(Values) 495 if t2 != IdentifierToken && t2 != DoesNotExistToken { 496 return nil, fmt.Errorf("found '%s', expected: identifier after ','", l2) 497 } 498 default: 499 return nil, fmt.Errorf("found '%s', expected: ',' or 'end of string'", l) 500 } 501 case EndOfStringToken: 502 return requirements, nil 503 default: 504 return nil, fmt.Errorf("found '%s', expected: !, identifier, or 'end of string'", lit) 505 } 506 } 507 } 508 509 func (p *Parser) parseRequirement() (*Requirement, error) { 510 key, operator, err := p.parseKeyAndInferOperator() 511 if err != nil { 512 return nil, err 513 } 514 if operator == ExistsOperator || operator == DoesNotExistOperator { // operator found lookahead set checked 515 return NewRequirement(key, operator, nil) 516 } 517 operator, err = p.parseOperator() 518 if err != nil { 519 return nil, err 520 } 521 var values sets.String 522 switch operator { 523 case InOperator, NotInOperator: 524 values, err = p.parseValues() 525 case EqualsOperator, DoubleEqualsOperator, NotEqualsOperator: 526 values, err = p.parseExactValue() 527 } 528 if err != nil { 529 return nil, err 530 } 531 return NewRequirement(key, operator, values) 532 533 } 534 535 // parseKeyAndInferOperator parse literals. 536 // in case of no operator '!, in, notin, ==, =, !=' are found 537 // the 'exists' operator is inferred 538 func (p *Parser) parseKeyAndInferOperator() (string, Operator, error) { 539 var operator Operator 540 tok, literal := p.consume(Values) 541 if tok == DoesNotExistToken { 542 operator = DoesNotExistOperator 543 tok, literal = p.consume(Values) 544 } 545 if tok != IdentifierToken { 546 err := fmt.Errorf("found '%s', expected: identifier", literal) 547 return "", "", err 548 } 549 if err := validateLabelKey(literal); err != nil { 550 return "", "", err 551 } 552 if t, _ := p.lookahead(Values); t == EndOfStringToken || t == CommaToken { 553 if operator != DoesNotExistOperator { 554 operator = ExistsOperator 555 } 556 } 557 return literal, operator, nil 558 } 559 560 // parseOperator return operator and eventually matchType 561 // matchType can be exact 562 func (p *Parser) parseOperator() (op Operator, err error) { 563 tok, lit := p.consume(KeyAndOperator) 564 switch tok { 565 // DoesNotExistToken shouldn't be here because it's a unary operator, not a binary operator 566 case InToken: 567 op = InOperator 568 case EqualsToken: 569 op = EqualsOperator 570 case DoubleEqualsToken: 571 op = DoubleEqualsOperator 572 case NotInToken: 573 op = NotInOperator 574 case NotEqualsToken: 575 op = NotEqualsOperator 576 default: 577 return "", fmt.Errorf("found '%s', expected: '=', '!=', '==', 'in', notin'", lit) 578 } 579 return op, nil 580 } 581 582 // parseValues parses the values for set based matching (x,y,z) 583 func (p *Parser) parseValues() (sets.String, error) { 584 tok, lit := p.consume(Values) 585 if tok != OpenParToken { 586 return nil, fmt.Errorf("found '%s' expected: '('", lit) 587 } 588 tok, lit = p.lookahead(Values) 589 switch tok { 590 case IdentifierToken, CommaToken: 591 s, err := p.parseIdentifiersList() // handles general cases 592 if err != nil { 593 return s, err 594 } 595 if tok, _ = p.consume(Values); tok != ClosedParToken { 596 return nil, fmt.Errorf("found '%s', expected: ')'", lit) 597 } 598 return s, nil 599 case ClosedParToken: // handles "()" 600 p.consume(Values) 601 return sets.NewString(""), nil 602 default: 603 return nil, fmt.Errorf("found '%s', expected: ',', ')' or identifier", lit) 604 } 605 } 606 607 // parseIdentifiersList parses a (possibly empty) list of 608 // of comma separated (possibly empty) identifiers 609 func (p *Parser) parseIdentifiersList() (sets.String, error) { 610 s := sets.NewString() 611 for { 612 tok, lit := p.consume(Values) 613 switch tok { 614 case IdentifierToken: 615 s.Insert(lit) 616 tok2, lit2 := p.lookahead(Values) 617 switch tok2 { 618 case CommaToken: 619 continue 620 case ClosedParToken: 621 return s, nil 622 default: 623 return nil, fmt.Errorf("found '%s', expected: ',' or ')'", lit2) 624 } 625 case CommaToken: // handled here since we can have "(," 626 if s.Len() == 0 { 627 s.Insert("") // to handle (, 628 } 629 tok2, _ := p.lookahead(Values) 630 if tok2 == ClosedParToken { 631 s.Insert("") // to handle ,) Double "" removed by StringSet 632 return s, nil 633 } 634 if tok2 == CommaToken { 635 p.consume(Values) 636 s.Insert("") // to handle ,, Double "" removed by StringSet 637 } 638 default: // it can be operator 639 return s, fmt.Errorf("found '%s', expected: ',', or identifier", lit) 640 } 641 } 642 } 643 644 // parseExactValue parses the only value for exact match style 645 func (p *Parser) parseExactValue() (sets.String, error) { 646 s := sets.NewString() 647 tok, lit := p.lookahead(Values) 648 if tok == EndOfStringToken || tok == CommaToken { 649 s.Insert("") 650 return s, nil 651 } 652 tok, lit = p.consume(Values) 653 if tok == IdentifierToken { 654 s.Insert(lit) 655 return s, nil 656 } 657 return nil, fmt.Errorf("found '%s', expected: identifier", lit) 658 } 659 660 // Parse takes a string representing a selector and returns a selector 661 // object, or an error. This parsing function differs from ParseSelector 662 // as they parse different selectors with different syntaxes. 663 // The input will cause an error if it does not follow this form: 664 // 665 // <selector-syntax> ::= <requirement> | <requirement> "," <selector-syntax> ] 666 // <requirement> ::= [!] KEY [ <set-based-restriction> | <exact-match-restriction> ] 667 // <set-based-restriction> ::= "" | <inclusion-exclusion> <value-set> 668 // <inclusion-exclusion> ::= <inclusion> | <exclusion> 669 // <exclusion> ::= "notin" 670 // <inclusion> ::= "in" 671 // <value-set> ::= "(" <values> ")" 672 // <values> ::= VALUE | VALUE "," <values> 673 // <exact-match-restriction> ::= ["="|"=="|"!="] VALUE 674 // KEY is a sequence of one or more characters following [ DNS_SUBDOMAIN "/" ] DNS_LABEL 675 // VALUE is a sequence of zero or more characters "([A-Za-z0-9_-\.])". Max length is 64 character. 676 // Delimiter is white space: (' ', '\t') 677 // Example of valid syntax: 678 // "x in (foo,,baz),y,z notin ()" 679 // 680 // Note: 681 // (1) Inclusion - " in " - denotes that the KEY exists and is equal to any of the 682 // VALUEs in its requirement 683 // (2) Exclusion - " notin " - denotes that the KEY is not equal to any 684 // of the VALUEs in its requirement or does not exist 685 // (3) The empty string is a valid VALUE 686 // (4) A requirement with just a KEY - as in "y" above - denotes that 687 // the KEY exists and can be any VALUE. 688 // (5) A requirement with just !KEY requires that the KEY not exist. 689 // 690 func Parse(selector string) (Selector, error) { 691 p := &Parser{l: &Lexer{s: selector, pos: 0}} 692 items, error := p.parse() 693 if error == nil { 694 sort.Sort(ByKey(items)) // sort to grant determistic parsing 695 return LabelSelector(items), error 696 } 697 return nil, error 698 } 699 700 const qualifiedNameErrorMsg string = "must match regex [" + validation.DNS1123SubdomainFmt + " / ] " + validation.DNS1123LabelFmt 701 702 func validateLabelKey(k string) error { 703 if !validation.IsQualifiedName(k) { 704 return validation.NewInvalidError("label key", k, qualifiedNameErrorMsg) 705 } 706 return nil 707 } 708 709 func validateLabelValue(v string) error { 710 if !validation.IsValidLabelValue(v) { 711 return validation.NewInvalidError("label value", v, qualifiedNameErrorMsg) 712 } 713 return nil 714 } 715 716 // SelectorFromSet returns a Selector which will match exactly the given Set. A 717 // nil and empty Sets are considered equivalent to Everything(). 718 func SelectorFromSet(ls Set) Selector { 719 if ls == nil { 720 return LabelSelector{} 721 } 722 var requirements []Requirement 723 for label, value := range ls { 724 if r, err := NewRequirement(label, EqualsOperator, sets.NewString(value)); err != nil { 725 //TODO: double check errors when input comes from serialization? 726 return LabelSelector{} 727 } else { 728 requirements = append(requirements, *r) 729 } 730 } 731 // sort to have deterministic string representation 732 sort.Sort(ByKey(requirements)) 733 return LabelSelector(requirements) 734 }