diff --git a/pkg/quota/v1/evaluator/core/persistent_volume_claims.go b/pkg/quota/v1/evaluator/core/persistent_volume_claims.go index 3cf3a2b0fa986..67517bded4461 100644 --- a/pkg/quota/v1/evaluator/core/persistent_volume_claims.go +++ b/pkg/quota/v1/evaluator/core/persistent_volume_claims.go @@ -161,6 +161,13 @@ func (p *pvcEvaluator) Usage(item runtime.Object) (corev1.ResourceList, error) { // charge for storage if request, found := pvc.Spec.Resources.Requests[corev1.ResourceStorage]; found { + roundedRequest := request.DeepCopy() + if !roundedRequest.RoundUp(0) { + // Ensure storage requests are counted as whole byte values, to pass resourcequota validation. + // See http://issue.k8s.io/94313 + request = roundedRequest + } + result[corev1.ResourceRequestsStorage] = request // charge usage to the storage class (if present) if len(storageClassRef) > 0 { diff --git a/pkg/quota/v1/evaluator/core/persistent_volume_claims_test.go b/pkg/quota/v1/evaluator/core/persistent_volume_claims_test.go index 284395e31546c..bb9e663385b6a 100644 --- a/pkg/quota/v1/evaluator/core/persistent_volume_claims_test.go +++ b/pkg/quota/v1/evaluator/core/persistent_volume_claims_test.go @@ -77,6 +77,12 @@ func TestPersistentVolumeClaimEvaluatorUsage(t *testing.T) { StorageClassName: &classGold, }) + validClaimWithNonIntegerStorage := validClaim.DeepCopy() + validClaimWithNonIntegerStorage.Spec.Resources.Requests[api.ResourceName(api.ResourceStorage)] = resource.MustParse("1001m") + + validClaimByStorageClassWithNonIntegerStorage := validClaimByStorageClass.DeepCopy() + validClaimByStorageClassWithNonIntegerStorage.Spec.Resources.Requests[api.ResourceName(api.ResourceStorage)] = resource.MustParse("1001m") + evaluator := NewPersistentVolumeClaimEvaluator(nil) testCases := map[string]struct { pvc *api.PersistentVolumeClaim @@ -100,6 +106,25 @@ func TestPersistentVolumeClaimEvaluatorUsage(t *testing.T) { generic.ObjectCountQuotaResourceNameFor(schema.GroupResource{Resource: "persistentvolumeclaims"}): resource.MustParse("1"), }, }, + + "pvc-usage-rounded": { + pvc: validClaimWithNonIntegerStorage, + usage: corev1.ResourceList{ + corev1.ResourceRequestsStorage: resource.MustParse("2"), // 1001m -> 2 + corev1.ResourcePersistentVolumeClaims: resource.MustParse("1"), + generic.ObjectCountQuotaResourceNameFor(schema.GroupResource{Resource: "persistentvolumeclaims"}): resource.MustParse("1"), + }, + }, + "pvc-usage-by-class-rounded": { + pvc: validClaimByStorageClassWithNonIntegerStorage, + usage: corev1.ResourceList{ + corev1.ResourceRequestsStorage: resource.MustParse("2"), // 1001m -> 2 + corev1.ResourcePersistentVolumeClaims: resource.MustParse("1"), + V1ResourceByStorageClass(classGold, corev1.ResourceRequestsStorage): resource.MustParse("2"), // 1001m -> 2 + V1ResourceByStorageClass(classGold, corev1.ResourcePersistentVolumeClaims): resource.MustParse("1"), + generic.ObjectCountQuotaResourceNameFor(schema.GroupResource{Resource: "persistentvolumeclaims"}): resource.MustParse("1"), + }, + }, } for testName, testCase := range testCases { actual, err := evaluator.Usage(testCase.pvc) @@ -107,7 +132,7 @@ func TestPersistentVolumeClaimEvaluatorUsage(t *testing.T) { t.Errorf("%s unexpected error: %v", testName, err) } if !quota.Equals(testCase.usage, actual) { - t.Errorf("%s expected: %v, actual: %v", testName, testCase.usage, actual) + t.Errorf("%s expected:\n%v\n, actual:\n%v", testName, testCase.usage, actual) } } }