Validate labelSelector in topologySpreadConstraints

Signed-off-by: maao <maao420691301@gmail.com>
This commit is contained in:
maao
2022-08-11 21:21:06 +08:00
parent 96fd7b1b50
commit a796707396
4 changed files with 129 additions and 6 deletions

View File

@@ -21,6 +21,7 @@ import (
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
metavalidation "k8s.io/apimachinery/pkg/apis/meta/v1/validation"
utilfeature "k8s.io/apiserver/pkg/util/feature"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/core/helper"
@@ -402,6 +403,17 @@ func haveSameExpandedDNSConfig(podSpec, oldPodSpec *api.PodSpec) bool {
return true
}
// hasInvalidTopologySpreadConstraintLabelSelector return true if spec.TopologySpreadConstraints have any entry with invalid labelSelector
func hasInvalidTopologySpreadConstraintLabelSelector(spec *api.PodSpec) bool {
for _, constraint := range spec.TopologySpreadConstraints {
errs := metavalidation.ValidateLabelSelector(constraint.LabelSelector, metavalidation.LabelSelectorValidationOptions{AllowInvalidLabelValueInSelector: false}, nil)
if len(errs) != 0 {
return true
}
}
return false
}
// GetValidationOptionsFromPodSpecAndMeta returns validation options based on pod specs and metadata
func GetValidationOptionsFromPodSpecAndMeta(podSpec, oldPodSpec *api.PodSpec, podMeta, oldPodMeta *metav1.ObjectMeta) apivalidation.PodValidationOptions {
// default pod validation options based on feature gate
@@ -412,8 +424,9 @@ func GetValidationOptionsFromPodSpecAndMeta(podSpec, oldPodSpec *api.PodSpec, po
// Do not allow pod spec to use non-integer multiple of huge page unit size default
AllowIndivisibleHugePagesValues: false,
// Allow pod spec with expanded DNS configuration
AllowExpandedDNSConfig: utilfeature.DefaultFeatureGate.Enabled(features.ExpandedDNSConfig) || haveSameExpandedDNSConfig(podSpec, oldPodSpec),
AllowInvalidLabelValueInSelector: false,
AllowExpandedDNSConfig: utilfeature.DefaultFeatureGate.Enabled(features.ExpandedDNSConfig) || haveSameExpandedDNSConfig(podSpec, oldPodSpec),
AllowInvalidLabelValueInSelector: false,
AllowInvalidTopologySpreadConstraintLabelSelector: false,
}
if oldPodSpec != nil {
@@ -431,7 +444,8 @@ func GetValidationOptionsFromPodSpecAndMeta(podSpec, oldPodSpec *api.PodSpec, po
opts.AllowIndivisibleHugePagesValues = usesIndivisibleHugePagesValues(oldPodSpec)
opts.AllowInvalidLabelValueInSelector = hasInvalidLabelValueInAffinitySelector(oldPodSpec)
// if old spec has invalid labelSelector in topologySpreadConstraint, we must allow it
opts.AllowInvalidTopologySpreadConstraintLabelSelector = hasInvalidTopologySpreadConstraintLabelSelector(oldPodSpec)
}
if oldPodMeta != nil && !opts.AllowInvalidPodDeletionCost {
// This is an update, so validate only if the existing object was valid.

View File

@@ -2176,3 +2176,63 @@ func TestDropSchedulingGates(t *testing.T) {
}
}
}
func TestValidateTopologySpreadConstraintLabelSelectorOption(t *testing.T) {
testCases := []struct {
name string
oldPodSpec *api.PodSpec
wantOption bool
}{
{
name: "Create",
wantOption: false,
},
{
name: "UpdateInvalidLabelSelector",
oldPodSpec: &api.PodSpec{
TopologySpreadConstraints: []api.TopologySpreadConstraint{
{
LabelSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{"NoUppercaseOrSpecialCharsLike=Equals": "foo"},
},
},
},
},
wantOption: true,
},
{
name: "UpdateValidLabelSelector",
oldPodSpec: &api.PodSpec{
TopologySpreadConstraints: []api.TopologySpreadConstraint{
{
LabelSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{"foo": "foo"},
},
},
},
},
wantOption: false,
},
{
name: "UpdateEmptyLabelSelector",
oldPodSpec: &api.PodSpec{
TopologySpreadConstraints: []api.TopologySpreadConstraint{
{
LabelSelector: nil,
},
},
},
wantOption: false,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
// Pod meta doesn't impact the outcome.
gotOptions := GetValidationOptionsFromPodSpecAndMeta(&api.PodSpec{}, tc.oldPodSpec, nil, nil)
if tc.wantOption != gotOptions.AllowInvalidTopologySpreadConstraintLabelSelector {
t.Errorf("Got AllowInvalidLabelValueInSelector=%t, want %t", gotOptions.AllowInvalidTopologySpreadConstraintLabelSelector, tc.wantOption)
}
})
}
}