Skip to content

Commit cfc845b

Browse files
authored
Merge pull request kubernetes#89747 from alvaroaleman/add-ass-validated-selector
apimachinery/pkg/labels: add SelectorFromSet
2 parents 60df45f + bec6f08 commit cfc845b

File tree

3 files changed

+56
-10
lines changed

3 files changed

+56
-10
lines changed

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

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,22 @@ func (ls Set) Get(label string) string {
5757
return ls[label]
5858
}
5959

60-
// AsSelector converts labels into a selectors.
60+
// AsSelector converts labels into a selectors. It does not
61+
// perform any validation, which means the server will reject
62+
// the request if the Set contains invalid values.
6163
func (ls Set) AsSelector() Selector {
6264
return SelectorFromSet(ls)
6365
}
6466

67+
// AsValidatedSelector converts labels into a selectors.
68+
// The Set is validated client-side, which allows to catch errors early.
69+
func (ls Set) AsValidatedSelector() (Selector, error) {
70+
return ValidatedSelectorFromSet(ls)
71+
}
72+
6573
// AsSelectorPreValidated converts labels into a selector, but
66-
// assumes that labels are already validated and thus don't
67-
// preform any validation.
74+
// assumes that labels are already validated and thus doesn't
75+
// perform any validation.
6876
// According to our measurements this is significantly faster
6977
// in codepaths that matter at high scale.
7078
func (ls Set) AsSelectorPreValidated() Selector {

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

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -869,23 +869,30 @@ func validateLabelValue(k, v string) error {
869869

870870
// SelectorFromSet returns a Selector which will match exactly the given Set. A
871871
// nil and empty Sets are considered equivalent to Everything().
872+
// It does not perform any validation, which means the server will reject
873+
// the request if the Set contains invalid values.
872874
func SelectorFromSet(ls Set) Selector {
875+
return SelectorFromValidatedSet(ls)
876+
}
877+
878+
// ValidatedSelectorFromSet returns a Selector which will match exactly the given Set. A
879+
// nil and empty Sets are considered equivalent to Everything().
880+
// The Set is validated client-side, which allows to catch errors early.
881+
func ValidatedSelectorFromSet(ls Set) (Selector, error) {
873882
if ls == nil || len(ls) == 0 {
874-
return internalSelector{}
883+
return internalSelector{}, nil
875884
}
876885
requirements := make([]Requirement, 0, len(ls))
877886
for label, value := range ls {
878887
r, err := NewRequirement(label, selection.Equals, []string{value})
879-
if err == nil {
880-
requirements = append(requirements, *r)
881-
} else {
882-
//TODO: double check errors when input comes from serialization?
883-
return internalSelector{}
888+
if err != nil {
889+
return nil, err
884890
}
891+
requirements = append(requirements, *r)
885892
}
886893
// sort to have deterministic string representation
887894
sort.Sort(ByKey(requirements))
888-
return internalSelector(requirements)
895+
return internalSelector(requirements), nil
889896
}
890897

891898
// SelectorFromValidatedSet returns a Selector which will match exactly the given Set.

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

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package labels
1818

1919
import (
20+
"fmt"
2021
"reflect"
2122
"strings"
2223
"testing"
@@ -708,3 +709,33 @@ func TestRequiresExactMatch(t *testing.T) {
708709
})
709710
}
710711
}
712+
713+
func TestValidatedSelectorFromSet(t *testing.T) {
714+
tests := []struct {
715+
name string
716+
input Set
717+
expectedSelector internalSelector
718+
expectedError error
719+
}{
720+
{
721+
name: "Simple Set, no error",
722+
input: Set{"key": "val"},
723+
expectedSelector: internalSelector([]Requirement{{key: "key", operator: selection.Equals, strValues: []string{"val"}}}),
724+
},
725+
{
726+
name: "Invalid Set, value too long",
727+
input: Set{"Key": "axahm2EJ8Phiephe2eixohbee9eGeiyees1thuozi1xoh0GiuH3diewi8iem7Nui"},
728+
expectedError: fmt.Errorf(`invalid label value: "axahm2EJ8Phiephe2eixohbee9eGeiyees1thuozi1xoh0GiuH3diewi8iem7Nui": at key: "Key": must be no more than 63 characters`),
729+
},
730+
}
731+
732+
for _, tc := range tests {
733+
selector, err := ValidatedSelectorFromSet(tc.input)
734+
if !reflect.DeepEqual(err, tc.expectedError) {
735+
t.Fatalf("expected error %v, got error %v", tc.expectedError, err)
736+
}
737+
if err == nil && !reflect.DeepEqual(selector, tc.expectedSelector) {
738+
t.Errorf("expected selector %v, got selector %v", tc.expectedSelector, selector)
739+
}
740+
}
741+
}

0 commit comments

Comments
 (0)