Skip to content

Commit 5a23bff

Browse files
committed
add RequiresExactMatch for label.Selector
Signed-off-by: shaloulcy <[email protected]>
1 parent 36acfec commit 5a23bff

File tree

2 files changed

+107
-6
lines changed

2 files changed

+107
-6
lines changed

staging/src/k8s.io/apimachinery/pkg/labels/selector.go

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ type Selector interface {
5454

5555
// Make a deep copy of the selector.
5656
DeepCopySelector() Selector
57+
58+
// RequiresExactMatch allows a caller to introspect whether a given selector
59+
// requires a single specific label to be set, and if so returns the value it
60+
// requires.
61+
RequiresExactMatch(label string) (value string, found bool)
5762
}
5863

5964
// Everything returns a selector that matches all labels.
@@ -63,12 +68,13 @@ func Everything() Selector {
6368

6469
type nothingSelector struct{}
6570

66-
func (n nothingSelector) Matches(_ Labels) bool { return false }
67-
func (n nothingSelector) Empty() bool { return false }
68-
func (n nothingSelector) String() string { return "" }
69-
func (n nothingSelector) Add(_ ...Requirement) Selector { return n }
70-
func (n nothingSelector) Requirements() (Requirements, bool) { return nil, false }
71-
func (n nothingSelector) DeepCopySelector() Selector { return n }
71+
func (n nothingSelector) Matches(_ Labels) bool { return false }
72+
func (n nothingSelector) Empty() bool { return false }
73+
func (n nothingSelector) String() string { return "" }
74+
func (n nothingSelector) Add(_ ...Requirement) Selector { return n }
75+
func (n nothingSelector) Requirements() (Requirements, bool) { return nil, false }
76+
func (n nothingSelector) DeepCopySelector() Selector { return n }
77+
func (n nothingSelector) RequiresExactMatch(label string) (value string, found bool) { return "", false }
7278

7379
// Nothing returns a selector that matches no labels
7480
func Nothing() Selector {
@@ -358,6 +364,23 @@ func (lsel internalSelector) String() string {
358364
return strings.Join(reqs, ",")
359365
}
360366

367+
// RequiresExactMatch introspect whether a given selector requires a single specific field
368+
// to be set, and if so returns the value it requires.
369+
func (lsel internalSelector) RequiresExactMatch(label string) (value string, found bool) {
370+
for ix := range lsel {
371+
if lsel[ix].key == label {
372+
switch lsel[ix].operator {
373+
case selection.Equals, selection.DoubleEquals, selection.In:
374+
if len(lsel[ix].strValues) == 1 {
375+
return lsel[ix].strValues[0], true
376+
}
377+
}
378+
return "", false
379+
}
380+
}
381+
return "", false
382+
}
383+
361384
// Token represents constant definition for lexer token
362385
type Token int
363386

staging/src/k8s.io/apimachinery/pkg/labels/selector_test.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -630,3 +630,81 @@ func BenchmarkSelectorFromValidatedSet(b *testing.B) {
630630
}
631631
}
632632
}
633+
634+
func TestRequiresExactMatch(t *testing.T) {
635+
testCases := []struct {
636+
name string
637+
sel Selector
638+
label string
639+
expectedFound bool
640+
expectedValue string
641+
}{
642+
{
643+
name: "keyInOperatorExactMatch",
644+
sel: internalSelector{Requirement{"key", selection.In, []string{"value"}}},
645+
label: "key",
646+
expectedFound: true,
647+
expectedValue: "value",
648+
},
649+
{
650+
name: "keyInOperatorNotExactMatch",
651+
sel: internalSelector{Requirement{"key", selection.In, []string{"value", "value2"}}},
652+
label: "key",
653+
expectedFound: false,
654+
expectedValue: "",
655+
},
656+
{
657+
name: "keyInOperatorNotExactMatch",
658+
sel: internalSelector{
659+
Requirement{"key", selection.In, []string{"value", "value1"}},
660+
Requirement{"key2", selection.In, []string{"value2"}},
661+
},
662+
label: "key2",
663+
expectedFound: true,
664+
expectedValue: "value2",
665+
},
666+
{
667+
name: "keyEqualOperatorExactMatch",
668+
sel: internalSelector{Requirement{"key", selection.Equals, []string{"value"}}},
669+
label: "key",
670+
expectedFound: true,
671+
expectedValue: "value",
672+
},
673+
{
674+
name: "keyDoubleEqualOperatorExactMatch",
675+
sel: internalSelector{Requirement{"key", selection.DoubleEquals, []string{"value"}}},
676+
label: "key",
677+
expectedFound: true,
678+
expectedValue: "value",
679+
},
680+
{
681+
name: "keyNotEqualOperatorExactMatch",
682+
sel: internalSelector{Requirement{"key", selection.NotEquals, []string{"value"}}},
683+
label: "key",
684+
expectedFound: false,
685+
expectedValue: "",
686+
},
687+
{
688+
name: "keyEqualOperatorExactMatchFirst",
689+
sel: internalSelector{
690+
Requirement{"key", selection.In, []string{"value"}},
691+
Requirement{"key2", selection.In, []string{"value2"}},
692+
},
693+
label: "key",
694+
expectedFound: true,
695+
expectedValue: "value",
696+
},
697+
}
698+
for _, ts := range testCases {
699+
t.Run(ts.name, func(t *testing.T) {
700+
value, found := ts.sel.RequiresExactMatch(ts.label)
701+
if found != ts.expectedFound {
702+
t.Errorf("Expected match %v, found %v", ts.expectedFound, found)
703+
}
704+
if found && value != ts.expectedValue {
705+
t.Errorf("Expected value %v, found %v", ts.expectedValue, value)
706+
}
707+
708+
})
709+
}
710+
}

0 commit comments

Comments
 (0)