Merge pull request #8140 from vishh/namespace

Update Namespace names to follow DNS label format
pull/6/head
Tim Hockin 2015-05-19 11:25:32 -07:00
commit cb49843ccb
7 changed files with 51 additions and 11 deletions

View File

@ -51,7 +51,7 @@ type Namespace struct {
}
```
A *Namespace* name is a DNS compatible subdomain.
A *Namespace* name is a DNS compatible label.
A *Namespace* must exist prior to associating content with it.

View File

@ -99,7 +99,7 @@ type ObjectMeta struct {
// equivalent to the "default" namespace, but "default" is the canonical representation.
// Not all objects are required to be scoped to a namespace - the value of this field for
// those objects will be empty.
Namespace string `json:"namespace,omitempty" description:"namespace of the object; cannot be updated"`
Namespace string `json:"namespace,omitempty" description:"namespace of the object; must be a DNS_LABEL; cannot be updated"`
// SelfLink is a URL representing this object.
SelfLink string `json:"selfLink,omitempty" description:"URL for the object; populated by the system, read-only"`

View File

@ -578,7 +578,7 @@ type TypeMeta struct {
SelfLink string `json:"selfLink,omitempty" description:"URL for the object; populated by the system, read-only"`
ResourceVersion uint64 `json:"resourceVersion,omitempty" description:"string that identifies the internal version of this object that can be used by clients to determine when objects have changed; populated by the system, read-only; value must be treated as opaque by clients and passed unmodified back to the server: http://docs.k8s.io/api-conventions.md#concurrency-control-and-consistency"`
APIVersion string `json:"apiVersion,omitempty" description:"version of the schema the object should have"`
Namespace string `json:"namespace,omitempty" description:"namespace to which the object belongs; must be a DNS_SUBDOMAIN; 'default' by default; cannot be updated"`
Namespace string `json:"namespace,omitempty" description:"namespace to which the object belongs; must be a DNS_LABEL; 'default' by default; cannot be updated"`
// DeletionTimestamp is the time after which this resource will be deleted. This
// field is set by the server when a graceful deletion is requested by the user, and is not

View File

@ -572,7 +572,7 @@ type TypeMeta struct {
SelfLink string `json:"selfLink,omitempty" description:"URL for the object; populated by the system, read-only"`
ResourceVersion uint64 `json:"resourceVersion,omitempty" description:"string that identifies the internal version of this object that can be used by clients to determine when objects have changed; populated by the system, read-only; value must be treated as opaque by clients and passed unmodified back to the server: http://docs.k8s.io/api-conventions.md#concurrency-control-and-consistency"`
APIVersion string `json:"apiVersion,omitempty" description:"version of the schema the object should have"`
Namespace string `json:"namespace,omitempty" description:"namespace to which the object belongs; must be a DNS_SUBDOMAIN; 'default' by default; cannot be updated"`
Namespace string `json:"namespace,omitempty" description:"namespace to which the object belongs; must be a DNS_LABEL; 'default' by default; cannot be updated"`
// DeletionTimestamp is the time after which this resource will be deleted. This
// field is set by the server when a graceful deletion is requested by the user, and is not

View File

@ -99,7 +99,7 @@ type ObjectMeta struct {
// equivalent to the "default" namespace, but "default" is the canonical representation.
// Not all objects are required to be scoped to a namespace - the value of this field for
// those objects will be empty.
Namespace string `json:"namespace,omitempty" description:"namespace of the object; cannot be updated"`
Namespace string `json:"namespace,omitempty" description:"namespace of the object; must be a DNS_LABEL; cannot be updated"`
// SelfLink is a URL representing this object.
SelfLink string `json:"selfLink,omitempty" description:"URL for the object; populated by the system, read-only"`

View File

@ -129,7 +129,7 @@ func ValidateNodeName(name string, prefix bool) (bool, string) {
// Prefix indicates this name will be used as part of generation, in which case
// trailing dashes are allowed.
func ValidateNamespaceName(name string, prefix bool) (bool, string) {
return nameIsDNSSubdomain(name, prefix)
return nameIsDNSLabel(name, prefix)
}
// ValidateLimitRangeName can be used to check whether the given limit range name is valid.
@ -179,6 +179,17 @@ func nameIsDNSSubdomain(name string, prefix bool) (bool, string) {
return false, dnsSubdomainErrorMsg
}
// nameIsDNSLabel is a ValidateNameFunc for names that must be a DNS 1123 label.
func nameIsDNSLabel(name string, prefix bool) (bool, string) {
if prefix {
name = maskTrailingDash(name)
}
if util.IsDNS1123Label(name) {
return true, ""
}
return false, dns1123LabelErrorMsg
}
// nameIsDNS952Label is a ValidateNameFunc for names that must be a DNS 952 label.
func nameIsDNS952Label(name string, prefix bool) (bool, string) {
if prefix {
@ -213,8 +224,8 @@ func ValidateObjectMeta(meta *api.ObjectMeta, requiresNamespace bool, nameFn Val
if requiresNamespace {
if len(meta.Namespace) == 0 {
allErrs = append(allErrs, errs.NewFieldRequired("namespace"))
} else if !util.IsDNS1123Subdomain(meta.Namespace) {
allErrs = append(allErrs, errs.NewFieldInvalid("namespace", meta.Namespace, dnsSubdomainErrorMsg))
} else if ok, _ := ValidateNamespaceName(meta.Namespace, false); !ok {
allErrs = append(allErrs, errs.NewFieldInvalid("namespace", meta.Namespace, dns1123LabelErrorMsg))
}
} else {
if len(meta.Namespace) != 0 {

View File

@ -17,6 +17,7 @@ limitations under the License.
package validation
import (
"math/rand"
"strings"
"testing"
"time"
@ -54,6 +55,34 @@ func TestValidateObjectMetaCustomName(t *testing.T) {
}
}
// Ensure namespace names follow dns label format
func TestValidateObjectMetaNamespaces(t *testing.T) {
errs := ValidateObjectMeta(&api.ObjectMeta{Name: "test", Namespace: "foo.bar"}, false, func(s string, prefix bool) (bool, string) {
return true, ""
})
if len(errs) != 1 {
t.Fatalf("unexpected errors: %v", errs)
}
if !strings.Contains(errs[0].Error(), "invalid value 'foo.bar'") {
t.Errorf("unexpected error message: %v", errs)
}
maxLength := 63
letters := []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
b := make([]rune, maxLength+1)
for i := range b {
b[i] = letters[rand.Intn(len(letters))]
}
errs = ValidateObjectMeta(&api.ObjectMeta{Name: "test", Namespace: string(b)}, false, func(s string, prefix bool) (bool, string) {
return true, ""
})
if len(errs) != 1 {
t.Fatalf("unexpected errors: %v", errs)
}
if !strings.Contains(errs[0].Error(), "invalid value") {
t.Errorf("unexpected error message: %v", errs)
}
}
func TestValidateObjectMetaUpdateIgnoresCreationTimestamp(t *testing.T) {
if errs := ValidateObjectMetaUpdate(
&api.ObjectMeta{Name: "test", ResourceVersion: "1", CreationTimestamp: util.NewTime(time.Unix(10, 0))},
@ -2517,7 +2546,7 @@ func TestValidateLimitRange(t *testing.T) {
},
"invalid Namespace": {
api.LimitRange{ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: "^Invalid"}, Spec: spec},
dnsSubdomainErrorMsg,
dns1123LabelErrorMsg,
},
}
for k, v := range errorCases {
@ -2584,7 +2613,7 @@ func TestValidateResourceQuota(t *testing.T) {
},
"invalid Namespace": {
api.ResourceQuota{ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: "^Invalid"}, Spec: spec},
dnsSubdomainErrorMsg,
dns1123LabelErrorMsg,
},
}
for k, v := range errorCases {
@ -3042,7 +3071,7 @@ func TestValidateEndpoints(t *testing.T) {
"invalid namespace": {
endpoints: api.Endpoints{ObjectMeta: api.ObjectMeta{Name: "mysvc", Namespace: "no@#invalid.;chars\"allowed"}},
errorType: "FieldValueInvalid",
errorDetail: dnsSubdomainErrorMsg,
errorDetail: dns1123LabelErrorMsg,
},
"invalid name": {
endpoints: api.Endpoints{ObjectMeta: api.ObjectMeta{Name: "-_Invliad^&Characters", Namespace: "namespace"}},