Change:
return allErrs } <del> // validateTopologySelectorLabelRequirement tests that the specified TopologySelectorLabelRequirement fields has valid data func validateTopologySelectorLabelRequirement(rq core.TopologySelectorLabelRequirement, fldPath *field.Path) field.ErrorList { </del> <ins> // validateTopologySelectorLabelRequirement tests that the specified TopologySelectorLabelRequirement fields has valid data, // and constructs a set containing all of its Values. func validateTopologySelectorLabelRequirement(rq core.TopologySelectorLabelRequirement, fldPath *field.Path) (sets.String, field.ErrorList) { </ins> allErrs := field.ErrorList{} <ins> valueSet := make(sets.String) valuesPath := fldPath.Child("values") </ins> if len(rq.Values) == 0 { <del> allErrs = append(allErrs, field.Forbidden(fldPath.Child("values"), "must specify as least one value")) </del> <ins> allErrs = append(allErrs, field.Required(valuesPath, "")) </ins> } <ins> // Validate set property of Values field for i, value := range rq.Values { if valueSet.Has(value) { allErrs = append(allErrs, field.Duplicate(valuesPath.Index(i), value)) } valueSet.Insert(value) } </ins> allErrs = append(allErrs, unversionedvalidation.ValidateLabelName(rq.Key, fldPath.Child("key"))...) <del> return allErrs </del> <ins> return valueSet, allErrs </ins> } <del> // ValidateTopologySelectorTerm tests that the specified topology selector term has valid data func ValidateTopologySelectorTerm(term core.TopologySelectorTerm, fldPath *field.Path) field.ErrorList { </del> <ins> // ValidateTopologySelectorTerm tests that the specified topology selector term has valid data, // and constructs a map representing the term in raw form. func ValidateTopologySelectorTerm(term core.TopologySelectorTerm, fldPath *field.Path) (map[string]sets.String, field.ErrorList) { </ins> allErrs := field.ErrorList{} <ins> exprMap := make(map[string]sets.String) exprPath := fldPath.Child("matchLabelExpressions") </ins> if utilfeature.DefaultFeatureGate.Enabled(features.DynamicProvisioningScheduling) { <ins> // Allow empty MatchLabelExpressions, in case this field becomes optional in the future. </ins> for i, req := range term.MatchLabelExpressions { <del> allErrs = append(allErrs, validateTopologySelectorLabelRequirement(req, fldPath.Child("matchLabelExpressions").Index(i))...) </del> <ins> idxPath := exprPath.Index(i) valueSet, exprErrs := validateTopologySelectorLabelRequirement(req, idxPath) allErrs = append(allErrs, exprErrs...) // Validate no duplicate keys exist. if _, exists := exprMap[req.Key]; exists { allErrs = append(allErrs, field.Duplicate(idxPath.Child("key"), req.Key)) } exprMap[req.Key] = valueSet </ins> } } else if len(term.MatchLabelExpressions) != 0 { allErrs = append(allErrs, field.Forbidden(fldPath, "field is disabled by feature-gate DynamicProvisioningScheduling")) } <del> return allErrs </del> <ins> return exprMap, allErrs </ins> } // ValidateAvoidPodsInNodeAnnotations tests that the serialized AvoidPods in Node.Annotations has valid data

Discussion:
<!-- This form is for bug reports and feature requests ONLY! If you're looking for help check and the . If the matter is security related, please disclose it privately via --/kind feature The field essentially has the type , but currently there is no validation for set and map semantics, i.e. unique elements / keys. Having this validation at API level removes logic to validate at the volume plugin level. edit: this check will not be in cases where this makes it difficult to add other fields and make this field optional. /sig api-machinery /sig storage
/assign
Thanks for catching this. Would you be able to implement this for this release? We want to try to go beta if we can, and we won't be able to strengthen validation once that happens.
Yes will do!