Merge pull request #55532 from ianchakeres/validate-greater-than-zero-pv-pvc

Automatic merge from submit-queue (batch tested with PRs 55009, 55532, 55601, 52569, 55533). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

Validate that PV capacity and PVC capacity requests are positive, greater than 0

**What this PR does / why we need it**:  Zero (0) capacity PVs cause related pods to fail, and zero (0) capacity PVCs create zero (0) capacity PVs.

**Which issue(s) this PR fixes** :
Fixes #55553

**Special notes for your reviewer**:

**Release note**:

```release-note
Validate positive capacity for PVs and PVCs.
```
This commit is contained in:
Kubernetes Submit Queue 2017-11-14 00:09:48 -08:00 committed by GitHub
commit 3479549a62
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 51 additions and 5 deletions

View File

@ -62,7 +62,7 @@ const isNegativeErrorMsg string = apimachineryvalidation.IsNegativeErrorMsg
const isInvalidQuotaResource string = `must be a standard resource for quota`
const fieldImmutableErrorMsg string = genericvalidation.FieldImmutableErrorMsg
const isNotIntegerErrorMsg string = `must be an integer`
const isZeroErrorMsg string = `must be greater than zero`
const isNotPositiveErrorMsg string = `must be greater than zero`
var pdPartitionErrorMsg string = validation.InclusiveRangeError(1, 255)
var volumeModeErrorMsg string = "must be a number between 0 and 0777 (octal), both inclusive"
@ -315,6 +315,15 @@ func ValidateNonnegativeQuantity(value resource.Quantity, fldPath *field.Path) f
return allErrs
}
// Validates that a Quantity is positive
func ValidatePositiveQuantityValue(value resource.Quantity, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if value.Cmp(resource.Quantity{}) <= 0 {
allErrs = append(allErrs, field.Invalid(fldPath, value.String(), isNotPositiveErrorMsg))
}
return allErrs
}
func ValidateImmutableField(newVal, oldVal interface{}, fldPath *field.Path) field.ErrorList {
return genericvalidation.ValidateImmutableField(newVal, oldVal, fldPath)
}
@ -1342,6 +1351,7 @@ func ValidatePersistentVolume(pv *core.PersistentVolume) field.ErrorList {
capPath := specPath.Child("capacity")
for r, qty := range pv.Spec.Capacity {
allErrs = append(allErrs, validateBasicResource(qty, capPath.Key(string(r)))...)
allErrs = append(allErrs, ValidatePositiveQuantityValue(qty, capPath.Key(string(r)))...)
}
if len(string(pv.Spec.PersistentVolumeReclaimPolicy)) > 0 {
if !supportedReclaimPolicy.Has(string(pv.Spec.PersistentVolumeReclaimPolicy)) {
@ -1602,9 +1612,7 @@ func ValidatePersistentVolumeClaimSpec(spec *core.PersistentVolumeClaimSpec, fld
allErrs = append(allErrs, field.Required(fldPath.Child("resources").Key(string(core.ResourceStorage)), ""))
} else {
allErrs = append(allErrs, ValidateResourceQuantityValue(string(core.ResourceStorage), storageValue, fldPath.Child("resources").Key(string(core.ResourceStorage)))...)
if storageValue.Value() == int64(0) {
allErrs = append(allErrs, field.Invalid(fldPath, storageValue, isZeroErrorMsg))
}
allErrs = append(allErrs, ValidatePositiveQuantityValue(storageValue, fldPath.Child("resources").Key(string(core.ResourceStorage)))...)
}
if spec.StorageClassName != nil && len(*spec.StorageClassName) > 0 {

View File

@ -260,6 +260,21 @@ func TestValidatePersistentVolumes(t *testing.T) {
},
}),
},
"bad-volume-zero-capacity": {
isExpectedFailure: true,
volume: testVolume("foo", "", core.PersistentVolumeSpec{
Capacity: core.ResourceList{
core.ResourceName(core.ResourceStorage): resource.MustParse("0"),
},
AccessModes: []core.PersistentVolumeAccessMode{core.ReadWriteOnce},
PersistentVolumeSource: core.PersistentVolumeSource{
HostPath: &core.HostPathVolumeSource{
Path: "/foo",
Type: newHostPathType(string(core.HostPathDirectory)),
},
},
}),
},
"missing-accessmodes": {
isExpectedFailure: true,
volume: testVolume("goodname", "missing-accessmodes", core.PersistentVolumeSpec{
@ -732,6 +747,29 @@ func TestValidatePersistentVolumeClaim(t *testing.T) {
StorageClassName: &validClassName,
}),
},
"invalid-claim-zero-capacity": {
isExpectedFailure: true,
claim: testVolumeClaim("foo", "ns", core.PersistentVolumeClaimSpec{
Selector: &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: "key2",
Operator: "Exists",
},
},
},
AccessModes: []core.PersistentVolumeAccessMode{
core.ReadWriteOnce,
core.ReadOnlyMany,
},
Resources: core.ResourceRequirements{
Requests: core.ResourceList{
core.ResourceName(core.ResourceStorage): resource.MustParse("0G"),
},
},
StorageClassName: &validClassName,
}),
},
"invalid-label-selector": {
isExpectedFailure: true,
claim: testVolumeClaim("foo", "ns", core.PersistentVolumeClaimSpec{

View File

@ -494,7 +494,7 @@ func TestPersistentVolumeMultiPVs(t *testing.T) {
pvs := make([]*v1.PersistentVolume, maxPVs)
for i := 0; i < maxPVs; i++ {
// This PV will be claimed, released, and deleted
pvs[i] = createPV("pv-"+strconv.Itoa(i), "/tmp/foo"+strconv.Itoa(i), strconv.Itoa(i)+"G",
pvs[i] = createPV("pv-"+strconv.Itoa(i), "/tmp/foo"+strconv.Itoa(i), strconv.Itoa(i+1)+"G",
[]v1.PersistentVolumeAccessMode{v1.ReadWriteOnce}, v1.PersistentVolumeReclaimRetain)
}