When casting resource.Quantity to int64 it may overflow

We need to ensure that when converting resource.Quantity
to int64 it does not overflow and if it does, then an error is
returned back to the use rather than attempting expansion and
provisioning operations with scaled value.
This commit is contained in:
Hemant Kumar 2020-05-08 15:53:52 -04:00
parent 8f8ac98714
commit 75fdb6d554
14 changed files with 319 additions and 135 deletions

View File

@ -183,7 +183,13 @@ func (plugin *azureFilePlugin) ExpandVolumeDevice(
return oldSize, err
}
if err := azure.ResizeFileShare(resourceGroup, accountName, shareName, int(volumehelpers.RoundUpToGiB(newSize))); err != nil {
requestGiB, err := volumehelpers.RoundUpToGiBInt(newSize)
if err != nil {
return oldSize, err
}
if err := azure.ResizeFileShare(resourceGroup, accountName, shareName, requestGiB); err != nil {
return oldSize, err
}

View File

@ -158,7 +158,11 @@ func (a *azureFileProvisioner) Provision(selectedNode *v1.Node, allowedTopologie
var sku, resourceGroup, location, account, shareName string
capacity := a.options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)]
requestGiB := int(volumehelpers.RoundUpToGiB(capacity))
requestGiB, err := volumehelpers.RoundUpToGiBInt(capacity)
if err != nil {
return nil, err
}
secretNamespace := a.options.PVC.Namespace
// Apply ProvisionerParameters (case-insensitive). We leave validation of
// the values to the cloud provider.

View File

@ -101,7 +101,10 @@ func (util *GCEDiskUtil) CreateVolume(c *gcePersistentDiskProvisioner, node *v1.
name := volumeutil.GenerateVolumeName(c.options.ClusterName, c.options.PVName, 63) // GCE PD name can have up to 63 characters
capacity := c.options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)]
// GCE PDs are allocated in chunks of GiBs
requestGB := volumehelpers.RoundUpToGiB(capacity)
requestGB, err := volumehelpers.RoundUpToGiB(capacity)
if err != nil {
return "", 0, nil, "", err
}
// Apply Parameters.
// Values for parameter "replication-type" are canonicalized to lower case.
@ -159,7 +162,7 @@ func (util *GCEDiskUtil) CreateVolume(c *gcePersistentDiskProvisioner, node *v1.
name,
diskType,
selectedZones,
int64(requestGB),
requestGB,
*c.options.CloudTags)
if err != nil {
klog.V(2).Infof("Error creating regional GCE PD volume: %v", err)
@ -176,7 +179,7 @@ func (util *GCEDiskUtil) CreateVolume(c *gcePersistentDiskProvisioner, node *v1.
name,
diskType,
selectedZone,
int64(requestGB),
requestGB,
*c.options.CloudTags)
if err != nil {
klog.V(2).Infof("Error creating single-zone GCE PD volume: %v", err)

View File

@ -1212,11 +1212,18 @@ func (plugin *glusterfsPlugin) ExpandVolumeDevice(spec *volume.Spec, newSize res
}
// Find out delta size
expansionSize := resource.NewScaledQuantity((newSize.Value() - oldSize.Value()), 0)
expansionSizeGiB := int(volumehelpers.RoundUpToGiB(*expansionSize))
expansionSize := newSize
expansionSize.Sub(oldSize)
expansionSizeGiB, err := volumehelpers.RoundUpToGiBInt(expansionSize)
if err != nil {
return oldSize, err
}
// Find out requested Size
requestGiB := volumehelpers.RoundUpToGiB(newSize)
requestGiB, err := volumehelpers.RoundUpToGiB(newSize)
if err != nil {
return oldSize, err
}
//Check the existing volume size
currentVolumeInfo, err := cli.VolumeInfo(volumeID)

View File

@ -25,7 +25,7 @@ import (
volumeclient "github.com/libopenstorage/openstorage/api/client/volume"
osdspec "github.com/libopenstorage/openstorage/api/spec"
volumeapi "github.com/libopenstorage/openstorage/volume"
"k8s.io/api/core/v1"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
volumehelpers "k8s.io/cloud-provider/volume/helpers"
@ -60,7 +60,10 @@ func (util *portworxVolumeUtil) CreateVolume(p *portworxVolumeProvisioner) (stri
capacity := p.options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)]
// Portworx Volumes are specified in GiB
requestGiB := volumehelpers.RoundUpToGiB(capacity)
requestGiB, err := volumehelpers.RoundUpToGiB(capacity)
if err != nil {
return "", 0, nil, err
}
// Perform a best-effort parsing of parameters. Portworx 1.2.9 and later parses volume parameters from
// spec.VolumeLabels. So even if below SpecFromOpts() fails to parse certain parameters or
@ -211,7 +214,11 @@ func (util *portworxVolumeUtil) ResizeVolume(spec *volume.Spec, newSize resource
}
vol := vols[0]
newSizeInBytes := uint64(volumehelpers.RoundUpToGiB(newSize) * volumehelpers.GiB)
tBytes, ok := newSize.AsInt64()
if !ok {
return fmt.Errorf("quantity %v is too great, overflows int64", newSize)
}
newSizeInBytes := uint64(tBytes)
if vol.Spec.Size >= newSizeInBytes {
klog.Infof("Portworx volume: %s already at size: %d greater than or equal to new "+
"requested size: %d. Skipping resize.", spec.Name(), vol.Spec.Size, newSizeInBytes)

View File

@ -649,7 +649,11 @@ func (util *rbdUtil) ExpandImage(rbdExpander *rbdVolumeExpander, oldSize resourc
var err error
// Convert to MB that rbd defaults on.
sz := int(volumehelpers.RoundUpToMiB(newSize))
sz, err := volumehelpers.RoundUpToMiBInt(newSize)
if err != nil {
return oldSize, err
}
newVolSz := fmt.Sprintf("%d", sz)
newSizeQuant := resource.MustParse(fmt.Sprintf("%dMi", sz))

View File

@ -23,6 +23,7 @@ go_test(
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
"//staging/src/k8s.io/client-go/util/testing:go_default_library",
"//staging/src/k8s.io/cloud-provider/volume/helpers:go_default_library",
"//vendor/github.com/thecodeteam/goscaleio/types/v1:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
"//vendor/k8s.io/utils/exec/testing:go_default_library",

View File

@ -55,6 +55,10 @@ type sioVolume struct {
volume.MetricsNil
}
const (
minimumVolumeSizeGiB = 8
)
// *******************
// volume.Volume Impl
var _ volume.Volume = &sioVolume{}
@ -272,21 +276,17 @@ func (v *sioVolume) Provision(selectedNode *api.Node, allowedTopologies []api.To
// setup volume attrributes
genName := v.generateName("k8svol", 11)
eightGig := int64(8 * volumehelpers.GiB)
capacity := v.options.PVC.Spec.Resources.Requests[api.ResourceName(api.ResourceStorage)]
volSizeBytes := capacity.Value()
volSizeGB := int64(volumehelpers.RoundUpToGiB(capacity))
if volSizeBytes == 0 {
return nil, fmt.Errorf("invalid volume size of 0 specified")
volSizeGiB, err := volumehelpers.RoundUpToGiB(capacity)
if err != nil {
return nil, err
}
if volSizeBytes < eightGig {
eightGiBCapacity := resource.NewQuantity(eightGig, resource.BinarySI)
volSizeGB = int64(volumehelpers.RoundUpToGiB(*eightGiBCapacity))
klog.V(4).Info(log("capacity less than 8Gi found, adjusted to %dGi", volSizeGB))
if volSizeGiB < minimumVolumeSizeGiB {
volSizeGiB = minimumVolumeSizeGiB
klog.V(4).Info(log("capacity less than 8Gi found, adjusted to %dGi", volSizeGiB))
}
@ -298,7 +298,7 @@ func (v *sioVolume) Provision(selectedNode *api.Node, allowedTopologies []api.To
// create volume
volName := genName
vol, err := v.sioMgr.CreateVolume(volName, volSizeGB)
vol, err := v.sioMgr.CreateVolume(volName, volSizeGiB)
if err != nil {
klog.Error(log("provision failed while creating volume: %v", err))
return nil, err
@ -333,7 +333,7 @@ func (v *sioVolume) Provision(selectedNode *api.Node, allowedTopologies []api.To
AccessModes: v.options.PVC.Spec.AccessModes,
Capacity: api.ResourceList{
api.ResourceName(api.ResourceStorage): resource.MustParse(
fmt.Sprintf("%dGi", volSizeGB),
fmt.Sprintf("%dGi", volSizeGiB),
),
},
PersistentVolumeSource: api.PersistentVolumeSource{

View File

@ -23,6 +23,7 @@ import (
"strings"
"testing"
volumehelpers "k8s.io/cloud-provider/volume/helpers"
"k8s.io/klog"
api "k8s.io/api/core/v1"
@ -425,7 +426,7 @@ func TestVolumeProvisionerWithIncompleteConfig(t *testing.T) {
}
}
func TestVolumeProvisionerWithZeroCapacity(t *testing.T) {
func TestVolumeProvisionerWithMinimumCapacity(t *testing.T) {
plugMgr, tmpDir := newPluginMgr(t, makeScaleIOSecret(testSecret, testns))
defer os.RemoveAll(tmpDir)
@ -441,7 +442,7 @@ func TestVolumeProvisionerWithZeroCapacity(t *testing.T) {
options := volume.VolumeOptions{
ClusterName: "testcluster",
PVName: "pvc-sio-dynamic-vol",
PVC: volumetest.CreateTestPVC("0Mi", []api.PersistentVolumeAccessMode{api.ReadWriteOnce}),
PVC: volumetest.CreateTestPVC("100Mi", []api.PersistentVolumeAccessMode{api.ReadWriteOnce}),
PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimDelete,
}
options.PVC.Namespace = testns
@ -466,11 +467,25 @@ func TestVolumeProvisionerWithZeroCapacity(t *testing.T) {
}
sioVol.sioMgr.client = sio
_, err = provisioner.Provision(nil, nil)
if err == nil {
t.Fatalf("call to Provision() should fail with invalid capacity")
pv, err :=
provisioner.Provision(nil, nil)
if err != nil {
t.Fatalf("call to Provision() failed %v", err)
}
pvSize := pv.Spec.Capacity.Storage()
if pvSize == nil {
t.Fatalf("unexpected pv size: nil")
}
gibSize, err := volumehelpers.RoundUpToGiB(*pvSize)
if err != nil {
t.Fatalf("unexpected error while converting size to GiB: %v", err)
}
if gibSize != minimumVolumeSizeGiB {
t.Fatalf("expected GiB size to be %v got %v", minimumVolumeSizeGiB, gibSize)
}
}
func TestVolumeProvisionerWithSecretNamespace(t *testing.T) {

View File

@ -39,74 +39,88 @@ const (
KiB = 1024
)
// RoundUpToGB rounds up given quantity to chunks of GB
func RoundUpToGB(size resource.Quantity) int64 {
requestBytes := size.Value()
return roundUpSize(requestBytes, GB)
}
// RoundUpToGiB rounds up given quantity upto chunks of GiB
func RoundUpToGiB(size resource.Quantity) int64 {
requestBytes := size.Value()
return roundUpSize(requestBytes, GiB)
func RoundUpToGiB(size resource.Quantity) (int64, error) {
requestBytes, ok := size.AsInt64()
if !ok {
return 0, fmt.Errorf("quantity %v is too great, overflows int64", size)
}
return roundUpSize(requestBytes, GiB), nil
}
// RoundUpToMB rounds up given quantity to chunks of MB
func RoundUpToMB(size resource.Quantity) int64 {
requestBytes := size.Value()
return roundUpSize(requestBytes, MB)
func RoundUpToMB(size resource.Quantity) (int64, error) {
requestBytes, ok := size.AsInt64()
if !ok {
return 0, fmt.Errorf("quantity %v is too great, overflows int64", size)
}
return roundUpSize(requestBytes, MB), nil
}
// RoundUpToMiB rounds up given quantity upto chunks of MiB
func RoundUpToMiB(size resource.Quantity) int64 {
requestBytes := size.Value()
return roundUpSize(requestBytes, MiB)
func RoundUpToMiB(size resource.Quantity) (int64, error) {
requestBytes, ok := size.AsInt64()
if !ok {
return 0, fmt.Errorf("quantity %v is too great, overflows int64", size)
}
return roundUpSize(requestBytes, MiB), nil
}
// RoundUpToKB rounds up given quantity to chunks of KB
func RoundUpToKB(size resource.Quantity) int64 {
requestBytes := size.Value()
return roundUpSize(requestBytes, KB)
func RoundUpToKB(size resource.Quantity) (int64, error) {
requestBytes, ok := size.AsInt64()
if !ok {
return 0, fmt.Errorf("quantity %v is too great, overflows int64", size)
}
return roundUpSize(requestBytes, KB), nil
}
// RoundUpToKiB rounds up given quantity upto chunks of KiB
func RoundUpToKiB(size resource.Quantity) int64 {
requestBytes := size.Value()
return roundUpSize(requestBytes, KiB)
}
// RoundUpToGBInt rounds up given quantity to chunks of GB. It returns an
// int instead of an int64 and an error if there's overflow
func RoundUpToGBInt(size resource.Quantity) (int, error) {
requestBytes := size.Value()
return roundUpSizeInt(requestBytes, GB)
func RoundUpToKiB(size resource.Quantity) (int64, error) {
requestBytes, ok := size.AsInt64()
if !ok {
return 0, fmt.Errorf("quantity %v is too great, overflows int64", size)
}
return roundUpSize(requestBytes, KiB), nil
}
// RoundUpToGiBInt rounds up given quantity upto chunks of GiB. It returns an
// int instead of an int64 and an error if there's overflow
func RoundUpToGiBInt(size resource.Quantity) (int, error) {
requestBytes := size.Value()
requestBytes, ok := size.AsInt64()
if !ok {
return 0, fmt.Errorf("quantity %v is too great, overflows int64", size)
}
return roundUpSizeInt(requestBytes, GiB)
}
// RoundUpToMBInt rounds up given quantity to chunks of MB. It returns an
// int instead of an int64 and an error if there's overflow
func RoundUpToMBInt(size resource.Quantity) (int, error) {
requestBytes := size.Value()
requestBytes, ok := size.AsInt64()
if !ok {
return 0, fmt.Errorf("quantity %v is too great, overflows int64", size)
}
return roundUpSizeInt(requestBytes, MB)
}
// RoundUpToMiBInt rounds up given quantity upto chunks of MiB. It returns an
// int instead of an int64 and an error if there's overflow
func RoundUpToMiBInt(size resource.Quantity) (int, error) {
requestBytes := size.Value()
requestBytes, ok := size.AsInt64()
if !ok {
return 0, fmt.Errorf("quantity %v is too great, overflows int64", size)
}
return roundUpSizeInt(requestBytes, MiB)
}
// RoundUpToKBInt rounds up given quantity to chunks of KB. It returns an
// int instead of an int64 and an error if there's overflow
func RoundUpToKBInt(size resource.Quantity) (int, error) {
requestBytes := size.Value()
requestBytes, ok := size.AsInt64()
if !ok {
return 0, fmt.Errorf("quantity %v is too great, overflows int64", size)
}
return roundUpSizeInt(requestBytes, KB)
}
@ -117,6 +131,16 @@ func RoundUpToKiBInt(size resource.Quantity) (int, error) {
return roundUpSizeInt(requestBytes, KiB)
}
// RoundUpToGiBInt32 rounds up given quantity up to chunks of GiB. It returns an
// int32 instead of an int64 and an error if there's overflow
func RoundUpToGiBInt32(size resource.Quantity) (int32, error) {
requestBytes, ok := size.AsInt64()
if !ok {
return 0, fmt.Errorf("quantity %v is too great, overflows int64", size)
}
return roundUpSizeInt32(requestBytes, GiB)
}
// roundUpSizeInt calculates how many allocation units are needed to accommodate
// a volume of given size. It returns an int instead of an int64 and an error if
// there's overflow
@ -129,6 +153,18 @@ func roundUpSizeInt(volumeSizeBytes int64, allocationUnitBytes int64) (int, erro
return roundedUpInt, nil
}
// roundUpSizeInt32 calculates how many allocation units are needed to accommodate
// a volume of given size. It returns an int32 instead of an int64 and an error if
// there's overflow
func roundUpSizeInt32(volumeSizeBytes int64, allocationUnitBytes int64) (int32, error) {
roundedUp := roundUpSize(volumeSizeBytes, allocationUnitBytes)
roundedUpInt32 := int32(roundedUp)
if int64(roundedUpInt32) != roundedUp {
return 0, fmt.Errorf("quantity %v is too great, overflows int32", roundedUp)
}
return roundedUpInt32, nil
}
// roundUpSize calculates how many allocation units are needed to accommodate
// a volume of given size. E.g. when user wants 1500MiB volume, while AWS EBS
// allocates volumes in gibibyte-sized chunks,

View File

@ -22,61 +22,12 @@ import (
"k8s.io/apimachinery/pkg/api/resource"
)
func Test_RoundUpToGB(t *testing.T) {
testcases := []struct {
name string
resource resource.Quantity
roundedVal int64
}{
{
name: "round Ki to GB",
resource: resource.MustParse("1000Ki"),
roundedVal: int64(1),
},
{
name: "round k to GB",
resource: resource.MustParse("1000k"),
roundedVal: int64(1),
},
{
name: "round Mi to GB",
resource: resource.MustParse("1000Mi"),
roundedVal: int64(2),
},
{
name: "round M to GB",
resource: resource.MustParse("1000M"),
roundedVal: int64(1),
},
{
name: "round G to GB",
resource: resource.MustParse("1000G"),
roundedVal: int64(1000),
},
{
name: "round Gi to GB",
resource: resource.MustParse("1000Gi"),
roundedVal: int64(1074),
},
}
for _, test := range testcases {
t.Run(test.name, func(t *testing.T) {
val := RoundUpToGB(test.resource)
if val != test.roundedVal {
t.Logf("actual rounded value: %d", val)
t.Logf("expected rounded value: %d", test.roundedVal)
t.Error("unexpected rounded value")
}
})
}
}
func Test_RoundUpToGiB(t *testing.T) {
testcases := []struct {
name string
resource resource.Quantity
roundedVal int64
name string
resource resource.Quantity
roundedVal int64
expectError bool
}{
{
name: "round Ki to GiB",
@ -108,11 +59,25 @@ func Test_RoundUpToGiB(t *testing.T) {
resource: resource.MustParse("1000Gi"),
roundedVal: int64(1000),
},
{
name: "round overflowed quantity to int64",
resource: resource.MustParse("73786976299133170k"),
roundedVal: int64(0),
expectError: true,
},
}
for _, test := range testcases {
t.Run(test.name, func(t *testing.T) {
val := RoundUpToGiB(test.resource)
val, err := RoundUpToGiB(test.resource)
if !test.expectError && err != nil {
t.Errorf("expected no error got: %v", err)
}
if test.expectError && err == nil {
t.Errorf("expected error but got nothing")
}
if val != test.roundedVal {
t.Logf("actual rounded value: %d", val)
t.Logf("expected rounded value: %d", test.roundedVal)
@ -124,9 +89,10 @@ func Test_RoundUpToGiB(t *testing.T) {
func Test_RoundUpToMB(t *testing.T) {
testcases := []struct {
name string
resource resource.Quantity
roundedVal int64
name string
resource resource.Quantity
roundedVal int64
expectError bool
}{
{
name: "round Ki to MB",
@ -158,11 +124,25 @@ func Test_RoundUpToMB(t *testing.T) {
resource: resource.MustParse("1000Gi"),
roundedVal: int64(1073742),
},
{
name: "round overflowed quantity to int64",
resource: resource.MustParse("73786976299133170k"),
roundedVal: int64(0),
expectError: true,
},
}
for _, test := range testcases {
t.Run(test.name, func(t *testing.T) {
val := RoundUpToMB(test.resource)
val, err := RoundUpToMB(test.resource)
if !test.expectError && err != nil {
t.Errorf("expected no error got: %v", err)
}
if test.expectError && err == nil {
t.Errorf("expected error but got nothing")
}
if val != test.roundedVal {
t.Logf("actual rounded value: %d", val)
t.Logf("expected rounded value: %d", test.roundedVal)
@ -174,9 +154,10 @@ func Test_RoundUpToMB(t *testing.T) {
func Test_RoundUpToMiB(t *testing.T) {
testcases := []struct {
name string
resource resource.Quantity
roundedVal int64
name string
resource resource.Quantity
roundedVal int64
expectError bool
}{
{
name: "round Ki to MiB",
@ -208,11 +189,25 @@ func Test_RoundUpToMiB(t *testing.T) {
resource: resource.MustParse("1000Gi"),
roundedVal: int64(1024000),
},
{
name: "round overflowed quantity to int64",
resource: resource.MustParse("73786976299133170k"),
roundedVal: int64(0),
expectError: true,
},
}
for _, test := range testcases {
t.Run(test.name, func(t *testing.T) {
val := RoundUpToMiB(test.resource)
val, err := RoundUpToMiB(test.resource)
if !test.expectError && err != nil {
t.Errorf("expected no error got: %v", err)
}
if test.expectError && err == nil {
t.Errorf("expected error but got nothing")
}
if val != test.roundedVal {
t.Logf("actual rounded value: %d", val)
t.Logf("expected rounded value: %d", test.roundedVal)
@ -224,9 +219,10 @@ func Test_RoundUpToMiB(t *testing.T) {
func Test_RoundUpToKB(t *testing.T) {
testcases := []struct {
name string
resource resource.Quantity
roundedVal int64
name string
resource resource.Quantity
roundedVal int64
expectError bool
}{
{
name: "round Ki to KB",
@ -258,11 +254,25 @@ func Test_RoundUpToKB(t *testing.T) {
resource: resource.MustParse("1000Gi"),
roundedVal: int64(1073741824),
},
{
name: "round overflowed quantity to int64",
resource: resource.MustParse("73786976299133170k"),
roundedVal: int64(0),
expectError: true,
},
}
for _, test := range testcases {
t.Run(test.name, func(t *testing.T) {
val := RoundUpToKB(test.resource)
val, err := RoundUpToKB(test.resource)
if !test.expectError && err != nil {
t.Errorf("expected no error got: %v", err)
}
if test.expectError && err == nil {
t.Errorf("expected error but got nothing")
}
if val != test.roundedVal {
t.Logf("actual rounded value: %d", val)
t.Logf("expected rounded value: %d", test.roundedVal)
@ -274,9 +284,10 @@ func Test_RoundUpToKB(t *testing.T) {
func Test_RoundUpToKiB(t *testing.T) {
testcases := []struct {
name string
resource resource.Quantity
roundedVal int64
name string
resource resource.Quantity
roundedVal int64
expectError bool
}{
{
name: "round Ki to KiB",
@ -308,11 +319,90 @@ func Test_RoundUpToKiB(t *testing.T) {
resource: resource.MustParse("1000Gi"),
roundedVal: int64(1048576000),
},
{
name: "round overflowed quantity to int64",
resource: resource.MustParse("73786976299133170k"),
roundedVal: int64(0),
expectError: true,
},
}
for _, test := range testcases {
t.Run(test.name, func(t *testing.T) {
val := RoundUpToKiB(test.resource)
val, err := RoundUpToKiB(test.resource)
if !test.expectError && err != nil {
t.Errorf("expected no error got: %v", err)
}
if test.expectError && err == nil {
t.Errorf("expected error but got nothing")
}
if val != test.roundedVal {
t.Logf("actual rounded value: %d", val)
t.Logf("expected rounded value: %d", test.roundedVal)
t.Error("unexpected rounded value")
}
})
}
}
func Test_RoundUpToGiBInt32(t *testing.T) {
testcases := []struct {
name string
resource resource.Quantity
roundedVal int32
expectError bool
}{
{
name: "round Ki to GiB",
resource: resource.MustParse("1000Ki"),
roundedVal: int32(1),
},
{
name: "round k to GiB",
resource: resource.MustParse("1000k"),
roundedVal: int32(1),
},
{
name: "round Mi to GiB",
resource: resource.MustParse("1000Mi"),
roundedVal: int32(1),
},
{
name: "round M to GiB",
resource: resource.MustParse("1000M"),
roundedVal: int32(1),
},
{
name: "round G to GiB",
resource: resource.MustParse("1000G"),
roundedVal: int32(932),
},
{
name: "round Gi to GiB",
resource: resource.MustParse("1000Gi"),
roundedVal: int32(1000),
},
{
name: "round overflowed quantity to int32",
resource: resource.MustParse("73786976299133170k"),
roundedVal: int32(0),
expectError: true,
},
}
for _, test := range testcases {
t.Run(test.name, func(t *testing.T) {
val, err := RoundUpToGiBInt32(test.resource)
if !test.expectError && err != nil {
t.Errorf("expected no error got: %v", err)
}
if test.expectError && err == nil {
t.Errorf("expected error but got nothing")
}
if val != test.roundedVal {
t.Logf("actual rounded value: %d", val)
t.Logf("expected rounded value: %d", test.roundedVal)

View File

@ -2815,7 +2815,10 @@ func (c *Cloud) ResizeDisk(
return oldSize, descErr
}
// AWS resizes in chunks of GiB (not GB)
requestGiB := volumehelpers.RoundUpToGiB(newSize)
requestGiB, err := volumehelpers.RoundUpToGiB(newSize)
if err != nil {
return oldSize, err
}
newSizeQuant := resource.MustParse(fmt.Sprintf("%dGi", requestGiB))
// If disk already if of greater or equal size than requested we return

View File

@ -284,7 +284,11 @@ func (c *ManagedDiskController) ResizeDisk(diskURI string, oldSize resource.Quan
}
// Azure resizes in chunks of GiB (not GB)
requestGiB := int32(volumehelpers.RoundUpToGiB(newSize))
requestGiB, err := volumehelpers.RoundUpToGiBInt32(newSize)
if err != nil {
return oldSize, err
}
newSizeQuant := resource.MustParse(fmt.Sprintf("%dGi", requestGiB))
klog.V(2).Infof("azureDisk - begin to resize disk(%s) with new size(%d), old size(%v)", diskName, requestGiB, oldSize)

View File

@ -25,7 +25,7 @@ import (
"net/http"
"strings"
"k8s.io/api/core/v1"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/types"
@ -809,7 +809,11 @@ func (g *Cloud) ResizeDisk(diskToResize string, oldSize resource.Quantity, newSi
}
// GCE resizes in chunks of GiBs
requestGIB := volumehelpers.RoundUpToGiB(newSize)
requestGIB, err := volumehelpers.RoundUpToGiB(newSize)
if err != nil {
return oldSize, err
}
newSizeQuant := resource.MustParse(fmt.Sprintf("%dGi", requestGIB))
// If disk is already of size equal or greater than requested size, we simply return