k3s/pkg/labels/selector.go

157 lines
3.5 KiB
Go
Raw Normal View History

2014-06-17 00:49:50 +00:00
/*
Copyright 2014 Google Inc. All rights reserved.
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 (
"fmt"
2014-06-20 17:03:56 +00:00
"sort"
2014-06-17 00:49:50 +00:00
"strings"
)
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
// 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
}
2014-06-18 23:47:41 +00:00
// Everything returns a selector that matches all labels.
func Everything() Selector {
return andTerm{}
2014-06-17 02:17:23 +00:00
}
type hasTerm struct {
label, value string
}
2014-06-17 00:49:50 +00:00
func (t *hasTerm) Matches(ls Labels) bool {
return ls.Get(t.label) == t.value
}
2014-06-17 00:49:50 +00:00
func (t *hasTerm) Empty() bool {
return false
}
func (t *hasTerm) String() string {
return fmt.Sprintf("%v=%v", t.label, t.value)
}
2014-06-17 00:49:50 +00:00
type notHasTerm struct {
label, value string
}
2014-06-17 00:49:50 +00:00
func (t *notHasTerm) Matches(ls Labels) bool {
return ls.Get(t.label) != t.value
2014-06-17 00:49:50 +00:00
}
func (t *notHasTerm) Empty() bool {
return false
}
func (t *notHasTerm) String() string {
return fmt.Sprintf("%v!=%v", t.label, t.value)
}
2014-06-18 23:47:41 +00:00
type andTerm []Selector
func (t andTerm) Matches(ls Labels) bool {
for _, q := range t {
if !q.Matches(ls) {
return false
2014-06-17 00:49:50 +00:00
}
}
return true
}
2014-06-17 00:49:50 +00:00
func (t andTerm) Empty() bool {
if t == nil {
return true
}
if len([]Selector(t)) == 0 {
return true
}
for i := range t {
if !t[i].Empty() {
return false
}
}
return true
}
func (t andTerm) String() string {
var terms []string
for _, q := range t {
terms = append(terms, q.String())
}
return strings.Join(terms, ",")
2014-06-17 00:49:50 +00:00
}
2014-06-18 23:47:41 +00:00
func try(selectorPiece, op string) (lhs, rhs string, ok bool) {
pieces := strings.Split(selectorPiece, op)
2014-06-17 00:49:50 +00:00
if len(pieces) == 2 {
return pieces[0], pieces[1], true
}
return "", "", false
}
// SelectorFromSet returns a Selector which will match exactly the given Set. A
// nil Set is considered equivalent to Everything().
2014-06-18 23:47:41 +00:00
func SelectorFromSet(ls Set) Selector {
if ls == nil {
return Everything()
}
items := make([]Selector, 0, len(ls))
for label, value := range ls {
items = append(items, &hasTerm{label: label, value: value})
2014-06-17 02:17:23 +00:00
}
if len(items) == 1 {
return items[0]
}
return andTerm(items)
2014-06-17 02:17:23 +00:00
}
2014-07-11 05:07:05 +00:00
// ParseSelector takes a string repsenting a selector and returns an
// object suitable for matching, or an error.
2014-06-18 23:47:41 +00:00
func ParseSelector(selector string) (Selector, error) {
parts := strings.Split(selector, ",")
2014-06-20 17:03:56 +00:00
sort.StringSlice(parts).Sort()
2014-06-18 23:47:41 +00:00
var items []Selector
2014-06-17 00:49:50 +00:00
for _, part := range parts {
if part == "" {
continue
}
if lhs, rhs, ok := try(part, "!="); ok {
items = append(items, &notHasTerm{label: lhs, value: rhs})
2014-06-17 00:49:50 +00:00
} else if lhs, rhs, ok := try(part, "=="); ok {
items = append(items, &hasTerm{label: lhs, value: rhs})
2014-06-17 00:49:50 +00:00
} else if lhs, rhs, ok := try(part, "="); ok {
items = append(items, &hasTerm{label: lhs, value: rhs})
2014-06-17 00:49:50 +00:00
} else {
2014-06-18 23:47:41 +00:00
return nil, fmt.Errorf("invalid selector: '%s'; can't understand '%s'", selector, part)
2014-06-17 00:49:50 +00:00
}
}
if len(items) == 1 {
return items[0], nil
2014-06-17 00:49:50 +00:00
}
return andTerm(items), nil
2014-06-17 00:49:50 +00:00
}