mirror of https://github.com/k3s-io/k3s
Merge pull request #715 from meirf/value-in-set-selector
structured message for selector; matching functionalitypull/6/head
commit
e8103e30a1
|
@ -20,6 +20,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Selector represents a label selector.
|
// Selector represents a label selector.
|
||||||
|
@ -105,6 +107,48 @@ func (t andTerm) String() string {
|
||||||
return strings.Join(terms, ",")
|
return strings.Join(terms, ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Operator represents a key's relationship
|
||||||
|
// to a set of values in a Requirement.
|
||||||
|
// TODO: Should also represent key's existence.
|
||||||
|
type Operator int
|
||||||
|
|
||||||
|
const (
|
||||||
|
IN Operator = iota + 1
|
||||||
|
NOT_IN
|
||||||
|
)
|
||||||
|
|
||||||
|
// LabelSelector only not named 'Selector' due
|
||||||
|
// to name conflict until Selector is deprecated.
|
||||||
|
type LabelSelector struct {
|
||||||
|
Requirements []Requirement
|
||||||
|
}
|
||||||
|
|
||||||
|
type Requirement struct {
|
||||||
|
key string
|
||||||
|
operator Operator
|
||||||
|
strValues util.StringSet
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Requirement) Matches(ls Labels) bool {
|
||||||
|
switch r.operator {
|
||||||
|
case IN:
|
||||||
|
return r.strValues.Has(ls.Get(r.key))
|
||||||
|
case NOT_IN:
|
||||||
|
return !r.strValues.Has(ls.Get(r.key))
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sg *LabelSelector) Matches(ls Labels) bool {
|
||||||
|
for _, req := range sg.Requirements {
|
||||||
|
if !req.Matches(ls) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func try(selectorPiece, op string) (lhs, rhs string, ok bool) {
|
func try(selectorPiece, op string) (lhs, rhs string, ok bool) {
|
||||||
pieces := strings.Split(selectorPiece, op)
|
pieces := strings.Split(selectorPiece, op)
|
||||||
if len(pieces) == 2 {
|
if len(pieces) == 2 {
|
||||||
|
|
|
@ -18,6 +18,8 @@ package labels
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSelectorParse(t *testing.T) {
|
func TestSelectorParse(t *testing.T) {
|
||||||
|
@ -163,3 +165,57 @@ func TestSetIsEmpty(t *testing.T) {
|
||||||
t.Errorf("Nested andTerm should not be empty")
|
t.Errorf("Nested andTerm should not be empty")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func expectMatchRequirement(t *testing.T, req Requirement, ls Set) {
|
||||||
|
if !req.Matches(ls) {
|
||||||
|
t.Errorf("Wanted '%+v' to match '%s', but it did not.\n", req, ls)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func expectNoMatchRequirement(t *testing.T, req Requirement, ls Set) {
|
||||||
|
if req.Matches(ls) {
|
||||||
|
t.Errorf("Wanted '%+v' to not match '%s', but it did.", req, ls)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRequirementMatches(t *testing.T) {
|
||||||
|
s := Set{"x": "foo", "y": "baz"}
|
||||||
|
a := Requirement{key: "x", operator: IN, strValues: util.NewStringSet("foo")}
|
||||||
|
b := Requirement{key: "x", operator: NOT_IN, strValues: util.NewStringSet("beta")}
|
||||||
|
c := Requirement{key: "y", operator: IN, strValues: nil}
|
||||||
|
d := Requirement{key: "y", strValues: util.NewStringSet("foo")}
|
||||||
|
expectMatchRequirement(t, a, s)
|
||||||
|
expectMatchRequirement(t, b, s)
|
||||||
|
expectNoMatchRequirement(t, c, s)
|
||||||
|
expectNoMatchRequirement(t, d, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func expectMatchLabSelector(t *testing.T, lsel LabelSelector, s Set) {
|
||||||
|
if !lsel.Matches(s) {
|
||||||
|
t.Errorf("Wanted '%+v' to match '%s', but it did not.\n", lsel, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func expectNoMatchLabSelector(t *testing.T, lsel LabelSelector, s Set) {
|
||||||
|
if lsel.Matches(s) {
|
||||||
|
t.Errorf("Wanted '%+v' to not match '%s', but it did.\n", lsel, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLabelSelectorMatches(t *testing.T) {
|
||||||
|
s := Set{"x": "foo", "y": "baz"}
|
||||||
|
allMatch := LabelSelector{
|
||||||
|
Requirements: []Requirement{
|
||||||
|
{key: "x", operator: IN, strValues: util.NewStringSet("foo")},
|
||||||
|
{key: "y", operator: NOT_IN, strValues: util.NewStringSet("alpha")},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
singleNonMatch := LabelSelector{
|
||||||
|
Requirements: []Requirement{
|
||||||
|
{key: "x", operator: IN, strValues: util.NewStringSet("foo")},
|
||||||
|
{key: "y", operator: IN, strValues: util.NewStringSet("alpha")},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
expectMatchLabSelector(t, allMatch, s)
|
||||||
|
expectNoMatchLabSelector(t, singleNonMatch, s)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue