mirror of https://github.com/k3s-io/k3s
Add namespacing for label keys
parent
d5a6a54391
commit
c857dc1196
|
@ -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"`
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"},
|
||||
|
|
Loading…
Reference in New Issue