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