Add StorageClassName validation

This commit is contained in:
Jan Safranek 2017-03-02 10:23:57 +01:00
parent 916a0a63dd
commit 39fa63d0a4
3 changed files with 58 additions and 1 deletions

View File

@ -247,6 +247,11 @@ var ValidateEndpointsName = NameIsDNSSubdomain
// ValidateClusterName can be used to check whether the given cluster name is valid. // ValidateClusterName can be used to check whether the given cluster name is valid.
var ValidateClusterName = genericvalidation.ValidateClusterName var ValidateClusterName = genericvalidation.ValidateClusterName
// ValidateClassName can be used to check whether the given class name is valid.
// It is defined here to avoid import cycle between pkg/apis/storage/validation
// (where it should be) and this file.
var ValidateClassName = NameIsDNSSubdomain
// TODO update all references to these functions to point to the genericvalidation ones // TODO update all references to these functions to point to the genericvalidation ones
// NameIsDNSSubdomain is a ValidateNameFunc for names that must be a DNS subdomain. // NameIsDNSSubdomain is a ValidateNameFunc for names that must be a DNS subdomain.
func NameIsDNSSubdomain(name string, prefix bool) []string { func NameIsDNSSubdomain(name string, prefix bool) []string {
@ -1194,6 +1199,12 @@ func ValidatePersistentVolume(pv *api.PersistentVolume) field.ErrorList {
allErrs = append(allErrs, field.Forbidden(specPath.Child("persistentVolumeReclaimPolicy"), "may not be 'recycle' for a hostPath mount of '/'")) allErrs = append(allErrs, field.Forbidden(specPath.Child("persistentVolumeReclaimPolicy"), "may not be 'recycle' for a hostPath mount of '/'"))
} }
if len(pv.Spec.StorageClassName) > 0 {
for _, msg := range ValidateClassName(pv.Spec.StorageClassName, false) {
allErrs = append(allErrs, field.Invalid(specPath.Child("storageClassName"), pv.Spec.StorageClassName, msg))
}
}
return allErrs return allErrs
} }
@ -1244,6 +1255,12 @@ func ValidatePersistentVolumeClaimSpec(spec *api.PersistentVolumeClaimSpec, fldP
} else { } else {
allErrs = append(allErrs, ValidateResourceQuantityValue(string(api.ResourceStorage), storageValue, fldPath.Child("resources").Key(string(api.ResourceStorage)))...) allErrs = append(allErrs, ValidateResourceQuantityValue(string(api.ResourceStorage), storageValue, fldPath.Child("resources").Key(string(api.ResourceStorage)))...)
} }
if spec.StorageClassName != nil && len(*spec.StorageClassName) > 0 {
for _, msg := range ValidateClassName(*spec.StorageClassName, false) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("storageClassName"), *spec.StorageClassName, msg))
}
}
return allErrs return allErrs
} }

View File

@ -80,6 +80,7 @@ func TestValidatePersistentVolumes(t *testing.T) {
PersistentVolumeSource: api.PersistentVolumeSource{ PersistentVolumeSource: api.PersistentVolumeSource{
HostPath: &api.HostPathVolumeSource{Path: "/foo"}, HostPath: &api.HostPathVolumeSource{Path: "/foo"},
}, },
StorageClassName: "valid",
}), }),
}, },
"good-volume-with-retain-policy": { "good-volume-with-retain-policy": {
@ -230,6 +231,19 @@ func TestValidatePersistentVolumes(t *testing.T) {
}, },
}), }),
}, },
"invalid-storage-class-name": {
isExpectedFailure: true,
volume: testVolume("invalid-storage-class-name", "", api.PersistentVolumeSpec{
Capacity: api.ResourceList{
api.ResourceName(api.ResourceStorage): resource.MustParse("10G"),
},
AccessModes: []api.PersistentVolumeAccessMode{api.ReadWriteOnce},
PersistentVolumeSource: api.PersistentVolumeSource{
HostPath: &api.HostPathVolumeSource{Path: "/foo"},
},
StorageClassName: "-invalid-",
}),
},
} }
for name, scenario := range scenarios { for name, scenario := range scenarios {
@ -301,6 +315,8 @@ func testVolumeClaimAnnotation(name string, namespace string, ann string, annval
} }
func TestValidatePersistentVolumeClaim(t *testing.T) { func TestValidatePersistentVolumeClaim(t *testing.T) {
invalidClassName := "-invalid-"
validClassName := "valid"
scenarios := map[string]struct { scenarios := map[string]struct {
isExpectedFailure bool isExpectedFailure bool
claim *api.PersistentVolumeClaim claim *api.PersistentVolumeClaim
@ -325,6 +341,7 @@ func TestValidatePersistentVolumeClaim(t *testing.T) {
api.ResourceName(api.ResourceStorage): resource.MustParse("10G"), api.ResourceName(api.ResourceStorage): resource.MustParse("10G"),
}, },
}, },
StorageClassName: &validClassName,
}), }),
}, },
"invalid-label-selector": { "invalid-label-selector": {
@ -428,6 +445,29 @@ func TestValidatePersistentVolumeClaim(t *testing.T) {
}, },
}), }),
}, },
"invalid-storage-class-name": {
isExpectedFailure: true,
claim: testVolumeClaim("foo", "ns", api.PersistentVolumeClaimSpec{
Selector: &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: "key2",
Operator: "Exists",
},
},
},
AccessModes: []api.PersistentVolumeAccessMode{
api.ReadWriteOnce,
api.ReadOnlyMany,
},
Resources: api.ResourceRequirements{
Requests: api.ResourceList{
api.ResourceName(api.ResourceStorage): resource.MustParse("10G"),
},
},
StorageClassName: &invalidClassName,
}),
},
} }
for name, scenario := range scenarios { for name, scenario := range scenarios {

View File

@ -28,7 +28,7 @@ import (
// ValidateStorageClass validates a StorageClass. // ValidateStorageClass validates a StorageClass.
func ValidateStorageClass(storageClass *storage.StorageClass) field.ErrorList { func ValidateStorageClass(storageClass *storage.StorageClass) field.ErrorList {
allErrs := apivalidation.ValidateObjectMeta(&storageClass.ObjectMeta, false, apivalidation.NameIsDNSSubdomain, field.NewPath("metadata")) allErrs := apivalidation.ValidateObjectMeta(&storageClass.ObjectMeta, false, apivalidation.ValidateClassName, field.NewPath("metadata"))
allErrs = append(allErrs, validateProvisioner(storageClass.Provisioner, field.NewPath("provisioner"))...) allErrs = append(allErrs, validateProvisioner(storageClass.Provisioner, field.NewPath("provisioner"))...)
allErrs = append(allErrs, validateParameters(storageClass.Parameters, field.NewPath("parameters"))...) allErrs = append(allErrs, validateParameters(storageClass.Parameters, field.NewPath("parameters"))...)