Add namespacing for label keys

pull/6/head
Tim Hockin 2014-11-20 14:27:11 +08:00
parent d5a6a54391
commit c857dc1196
3 changed files with 57 additions and 3 deletions

View File

@ -107,12 +107,21 @@ type ObjectMeta struct {
CreationTimestamp util.Time `json:"creationTimestamp,omitempty" yaml:"creationTimestamp,omitempty"`
// Labels are key value pairs that may be used to scope and select individual resources.
// Label keys are of the form:
// label-key ::= prefixed-name | name
// prefixed-name ::= prefix '/' name
// prefix ::= DNS_SUBDOMAIN
// name ::= DNS_LABEL
// The prefix is optional. If the prefix is not specified, the key is assumed to be private
// to the user. Other system components that wish to use labels must specify a prefix. The
// "kubernetes.io/" prefix is reserved for use by kubernetes components.
// TODO: replace map[string]string with labels.LabelSet type
Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
// Annotations are unstructured key value data stored with a resource that may be set by
// external tooling. They are not queryable and should be preserved when modifying
// objects.
// objects. Annotation keys have the same formatting restrictions as Label keys. See the
// comments on Labels for details.
Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"`
}

View File

@ -385,8 +385,20 @@ func ValidatePodSpec(spec *api.PodSpec) errs.ValidationErrorList {
func validateLabels(labels map[string]string, field string) errs.ValidationErrorList {
allErrs := errs.ValidationErrorList{}
for k := range labels {
if !util.IsDNS952Label(k) {
allErrs = append(allErrs, errs.NewFieldNotSupported(field, k))
var n, ns string
parts := strings.Split(k, "/")
switch len(parts) {
case 1:
n = parts[0]
case 2:
ns = parts[0]
n = parts[1]
default:
allErrs = append(allErrs, errs.NewFieldInvalid(field, k, ""))
continue
}
if (ns != "" && !util.IsDNSSubdomain(ns)) || !util.IsDNS952Label(n) {
allErrs = append(allErrs, errs.NewFieldInvalid(field, k, ""))
}
}
return allErrs

View File

@ -35,6 +35,39 @@ func expectPrefix(t *testing.T, prefix string, errs errors.ValidationErrorList)
}
}
func TestValidateLabels(t *testing.T) {
successCases := []map[string]string{
{"simple": "bar"},
{"now-with-dashes": "bar"},
{"simple/simple": "bar"},
{"now-with-dashes/simple": "bar"},
{"now-with-dashes/now-with-dashes": "bar"},
{"now.with.dots/simple": "bar"},
{"now-with.dashes-and.dots/simple": "bar"},
}
for i := range successCases {
errs := validateLabels(successCases[i], "field")
if len(errs) != 0 {
t.Errorf("case[%d] expected success, got %#v", i, errs)
}
}
errorCases := []map[string]string{
{"123cantbeginwithnumber": "bar"}, //invalid
{"NoUppercase123": "bar"}, //invalid
{"nospecialchars^=@": "bar"}, //invalid
{"cantendwithadash-": "bar"}, //invalid
{"rfc952-mustbe24charactersorless": "bar"}, //invalid
{"only/one/slash": "bar"},
}
for i := range errorCases {
errs := validateLabels(errorCases[i], "field")
if len(errs) != 1 {
t.Errorf("case[%d] expected failure", i)
}
}
}
func TestValidateVolumes(t *testing.T) {
successCase := []api.Volume{
{Name: "abc"},