Make IsValidLabelValue return error strings

This commit is contained in:
Tim Hockin 2015-12-15 22:27:13 -08:00
parent a0cc59f28a
commit 66d0d87829
11 changed files with 47 additions and 40 deletions

View File

@ -181,12 +181,12 @@ func SlaveAttributesToLabels(attrs []*mesos.Attribute) map[string]string {
} }
if errs := validation.IsQualifiedName(k); len(errs) != 0 { if errs := validation.IsQualifiedName(k); len(errs) != 0 {
log.V(3).Infof("ignoring invalid node label name %q", k, errs) log.V(3).Infof("ignoring invalid node label %q: %v", k, errs)
continue continue
} }
if !validation.IsValidLabelValue(v) { if errs := validation.IsValidLabelValue(v); len(errs) != 0 {
log.V(3).Infof("ignoring invalid node label %s value: %q", k, v) log.V(3).Infof("ignoring invalid node %s=%q: %v", k, v, errs)
continue continue
} }

View File

@ -17,17 +17,11 @@ limitations under the License.
package validation package validation
import ( import (
"fmt"
"k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/util/validation" "k8s.io/kubernetes/pkg/util/validation"
"k8s.io/kubernetes/pkg/util/validation/field" "k8s.io/kubernetes/pkg/util/validation/field"
) )
var (
labelValueErrorMsg string = fmt.Sprintf(`must have at most %d characters, matching regex %s: e.g. "MyValue" or ""`, validation.LabelValueMaxLength, validation.LabelValueFmt)
)
func ValidateLabelSelector(ps *unversioned.LabelSelector, fldPath *field.Path) field.ErrorList { func ValidateLabelSelector(ps *unversioned.LabelSelector, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{} allErrs := field.ErrorList{}
if ps == nil { if ps == nil {
@ -72,8 +66,8 @@ func ValidateLabels(labels map[string]string, fldPath *field.Path) field.ErrorLi
allErrs := field.ErrorList{} allErrs := field.ErrorList{}
for k, v := range labels { for k, v := range labels {
allErrs = append(allErrs, ValidateLabelName(k, fldPath)...) allErrs = append(allErrs, ValidateLabelName(k, fldPath)...)
if !validation.IsValidLabelValue(v) { for _, err := range validation.IsValidLabelValue(v) {
allErrs = append(allErrs, field.Invalid(fldPath, v, labelValueErrorMsg)) allErrs = append(allErrs, field.Invalid(fldPath, v, err))
} }
} }
return allErrs return allErrs

View File

@ -67,20 +67,22 @@ func TestValidateLabels(t *testing.T) {
} }
} }
labelValueErrorCases := []map[string]string{ labelValueErrorCases := []struct {
{"toolongvalue": strings.Repeat("a", 64)}, labels map[string]string
{"backslashesinvalue": "some\\bad\\value"}, expect string
{"nocommasallowed": "bad,value"}, }{
{"strangecharsinvalue": "?#$notsogood"}, {map[string]string{"toolongvalue": strings.Repeat("a", 64)}, "must be no more than"},
{map[string]string{"backslashesinvalue": "some\\bad\\value"}, "must match the regex"},
{map[string]string{"nocommasallowed": "bad,value"}, "must match the regex"},
{map[string]string{"strangecharsinvalue": "?#$notsogood"}, "must match the regex"},
} }
for i := range labelValueErrorCases { for i := range labelValueErrorCases {
errs := ValidateLabels(labelValueErrorCases[i], field.NewPath("field")) errs := ValidateLabels(labelValueErrorCases[i].labels, field.NewPath("field"))
if len(errs) != 1 { if len(errs) != 1 {
t.Errorf("case[%d] expected failure", i) t.Errorf("case[%d]: expected failure", i)
} else { } else {
detail := errs[0].Detail if !strings.Contains(errs[0].Detail, labelValueErrorCases[i].expect) {
if detail != labelValueErrorMsg { t.Errorf("case[%d]: error details do not include %q: %q", i, labelValueErrorCases[i].expect, errs[0].Detail)
t.Errorf("error detail %s should be equal %s", detail, labelValueErrorMsg)
} }
} }
} }

View File

@ -58,7 +58,6 @@ func InclusiveRangeErrorMsg(lo, hi int) string {
return fmt.Sprintf(`must be between %d and %d, inclusive`, lo, hi) return fmt.Sprintf(`must be between %d and %d, inclusive`, lo, hi)
} }
var labelValueErrorMsg string = fmt.Sprintf(`must have at most %d characters, matching regex %s: e.g. "MyValue" or ""`, validation.LabelValueMaxLength, validation.LabelValueFmt)
var DNSSubdomainErrorMsg string = fmt.Sprintf(`must be a DNS subdomain (at most %d characters, matching regex %s): e.g. "example.com"`, validation.DNS1123SubdomainMaxLength, validation.DNS1123SubdomainFmt) var DNSSubdomainErrorMsg string = fmt.Sprintf(`must be a DNS subdomain (at most %d characters, matching regex %s): e.g. "example.com"`, validation.DNS1123SubdomainMaxLength, validation.DNS1123SubdomainFmt)
var DNS1123LabelErrorMsg string = fmt.Sprintf(`must be a DNS label (at most %d characters, matching regex %s): e.g. "my-name"`, validation.DNS1123LabelMaxLength, validation.DNS1123LabelFmt) var DNS1123LabelErrorMsg string = fmt.Sprintf(`must be a DNS label (at most %d characters, matching regex %s): e.g. "my-name"`, validation.DNS1123LabelMaxLength, validation.DNS1123LabelFmt)
var DNS952LabelErrorMsg string = fmt.Sprintf(`must be a DNS 952 label (at most %d characters, matching regex %s): e.g. "my-name"`, validation.DNS952LabelMaxLength, validation.DNS952LabelFmt) var DNS952LabelErrorMsg string = fmt.Sprintf(`must be a DNS 952 label (at most %d characters, matching regex %s): e.g. "my-name"`, validation.DNS952LabelMaxLength, validation.DNS952LabelFmt)

View File

@ -124,9 +124,12 @@ func parseLabels(spec []string) (map[string]string, []string, error) {
for _, labelSpec := range spec { for _, labelSpec := range spec {
if strings.Index(labelSpec, "=") != -1 { if strings.Index(labelSpec, "=") != -1 {
parts := strings.Split(labelSpec, "=") parts := strings.Split(labelSpec, "=")
if len(parts) != 2 || len(parts[1]) == 0 || !validation.IsValidLabelValue(parts[1]) { if len(parts) != 2 || len(parts[1]) == 0 {
return nil, nil, fmt.Errorf("invalid label spec: %v", labelSpec) return nil, nil, fmt.Errorf("invalid label spec: %v", labelSpec)
} }
if errs := validation.IsValidLabelValue(parts[1]); len(errs) != 0 {
return nil, nil, fmt.Errorf("invalid label value: %q: %s", labelSpec, strings.Join(errs, ";"))
}
labels[parts[0]] = parts[1] labels[parts[0]] = parts[1]
} else if strings.HasSuffix(labelSpec, "-") { } else if strings.HasSuffix(labelSpec, "-") {
remove = append(remove, labelSpec[:len(labelSpec)-1]) remove = append(remove, labelSpec[:len(labelSpec)-1])

View File

@ -120,8 +120,8 @@ func InitNetworkPlugin(plugins []NetworkPlugin, networkPluginName string, host H
allErrs := []error{} allErrs := []error{}
for _, plugin := range plugins { for _, plugin := range plugins {
name := plugin.Name() name := plugin.Name()
if len(validation.IsQualifiedName(name)) != 0 { if errs := validation.IsQualifiedName(name); len(errs) != 0 {
allErrs = append(allErrs, fmt.Errorf("network plugin has invalid name: %#v", plugin)) allErrs = append(allErrs, fmt.Errorf("network plugin has invalid name: %q: %s", name, strings.Join(errs, ";")))
continue continue
} }

View File

@ -764,8 +764,6 @@ func parse(selector string) (internalSelector, error) {
return internalSelector(items), err return internalSelector(items), err
} }
var labelValueErrorMsg string = fmt.Sprintf(`must have at most %d characters, matching regex %s: e.g. "MyValue" or ""`, validation.LabelValueMaxLength, validation.LabelValueFmt)
func validateLabelKey(k string) error { func validateLabelKey(k string) error {
if errs := validation.IsQualifiedName(k); len(errs) != 0 { if errs := validation.IsQualifiedName(k); len(errs) != 0 {
return fmt.Errorf("invalid label key %q: %s", k, strings.Join(errs, "; ")) return fmt.Errorf("invalid label key %q: %s", k, strings.Join(errs, "; "))
@ -774,8 +772,8 @@ func validateLabelKey(k string) error {
} }
func validateLabelValue(v string) error { func validateLabelValue(v string) error {
if !validation.IsValidLabelValue(v) { if errs := validation.IsValidLabelValue(v); len(errs) != 0 {
return fmt.Errorf("invalid label value: %s", labelValueErrorMsg) return fmt.Errorf("invalid label value: %q: %s", v, strings.Join(errs, "; "))
} }
return nil return nil
} }

View File

@ -67,13 +67,24 @@ func IsQualifiedName(value string) []string {
return errs return errs
} }
const LabelValueFmt string = "(" + qualifiedNameFmt + ")?" const labelValueFmt string = "(" + qualifiedNameFmt + ")?"
const LabelValueMaxLength int = 63 const LabelValueMaxLength int = 63
var labelValueRegexp = regexp.MustCompile("^" + LabelValueFmt + "$") var labelValueMaxLengthString = strconv.Itoa(LabelValueMaxLength)
var labelValueRegexp = regexp.MustCompile("^" + labelValueFmt + "$")
func IsValidLabelValue(value string) bool { // IsValidLabelValue tests whether the value passed is a valid label value. If
return (len(value) <= LabelValueMaxLength && labelValueRegexp.MatchString(value)) // the value is not valid, a list of error strings is returned. Otherwise an
// empty list (or nil) is returned.
func IsValidLabelValue(value string) []string {
var errs []string
if len(value) > LabelValueMaxLength {
errs = append(errs, "must be no more than "+labelValueMaxLengthString+" characters")
}
if !labelValueRegexp.MatchString(value) {
errs = append(errs, "must match the regex "+labelValueFmt+" (e.g. 'MyValue' or 'my_value' or '12345')")
}
return errs
} }
const DNS1123LabelFmt string = "[a-z0-9]([-a-z0-9]*[a-z0-9])?" const DNS1123LabelFmt string = "[a-z0-9]([-a-z0-9]*[a-z0-9])?"

View File

@ -257,8 +257,8 @@ func TestIsValidLabelValue(t *testing.T) {
"", // empty value "", // empty value
} }
for i := range successCases { for i := range successCases {
if !IsValidLabelValue(successCases[i]) { if errs := IsValidLabelValue(successCases[i]); len(errs) != 0 {
t.Errorf("case %s expected success", successCases[i]) t.Errorf("case %s expected success: %v", successCases[i], errs)
} }
} }
@ -273,7 +273,7 @@ func TestIsValidLabelValue(t *testing.T) {
strings.Repeat("a", 64), // over the limit strings.Repeat("a", 64), // over the limit
} }
for i := range errorCases { for i := range errorCases {
if IsValidLabelValue(errorCases[i]) { if errs := IsValidLabelValue(errorCases[i]); len(errs) == 0 {
t.Errorf("case[%d] expected failure", i) t.Errorf("case[%d] expected failure", i)
} }
} }

View File

@ -272,8 +272,8 @@ func (pm *VolumePluginMgr) InitPlugins(plugins []VolumePlugin, host VolumeHost)
allErrs := []error{} allErrs := []error{}
for _, plugin := range plugins { for _, plugin := range plugins {
name := plugin.Name() name := plugin.Name()
if len(validation.IsQualifiedName(name)) != 0 { if errs := validation.IsQualifiedName(name); len(errs) != 0 {
allErrs = append(allErrs, fmt.Errorf("volume plugin has invalid name: %#v", plugin)) allErrs = append(allErrs, fmt.Errorf("volume plugin has invalid name: %q: %s", name, strings.Join(errs, ";")))
continue continue
} }

View File

@ -307,8 +307,8 @@ func (f *ConfigFactory) CreateFromKeys(predicateKeys, priorityKeys sets.String,
failureDomainArgs := strings.Split(f.FailureDomains, ",") failureDomainArgs := strings.Split(f.FailureDomains, ",")
for _, failureDomain := range failureDomainArgs { for _, failureDomain := range failureDomainArgs {
if len(utilvalidation.IsQualifiedName(failureDomain)) != 0 { if errs := utilvalidation.IsQualifiedName(failureDomain); len(errs) != 0 {
return nil, fmt.Errorf("invalid failure domain: %s", failureDomain) return nil, fmt.Errorf("invalid failure domain: %q: %s", failureDomain, strings.Join(errs, ";"))
} }
} }