diff --git a/pkg/volume/rbd/rbd_test.go b/pkg/volume/rbd/rbd_test.go index 46f56b9345..799194c076 100644 --- a/pkg/volume/rbd/rbd_test.go +++ b/pkg/volume/rbd/rbd_test.go @@ -682,3 +682,28 @@ func TestRequiresRemount(t *testing.T) { t.Errorf("Exepcted RequiresRemount to be false, got %t", has) } } + +func TestGetRbdImageSize(t *testing.T) { + for i, c := range []struct { + Output string + TargetSize int + }{ + { + Output: `{"name":"kubernetes-dynamic-pvc-18e7a4d9-050d-11e9-b905-548998f3478f","size":10737418240,"objects":2560,"order":22,"object_size":4194304,"block_name_prefix":"rbd_data.9f4ff7238e1f29","format":2}`, + TargetSize: 10240, + }, + { + Output: `{"name":"kubernetes-dynamic-pvc-070635bf-e33f-11e8-aab7-548998f3478f","size":1073741824,"objects":256,"order":22,"object_size":4194304,"block_name_prefix":"rbd_data.670ac4238e1f29","format":2}`, + TargetSize: 1024, + }, + } { + size, err := getRbdImageSize([]byte(c.Output)) + if err != nil { + t.Errorf("Case %d: getRbdImageSize failed: %v", i, err) + continue + } + if size != c.TargetSize { + t.Errorf("Case %d: unexpected size, wanted %d, got %d", i, c.TargetSize, size) + } + } +} diff --git a/pkg/volume/rbd/rbd_util.go b/pkg/volume/rbd/rbd_util.go index 2e3de22644..ec0dd7f2eb 100644 --- a/pkg/volume/rbd/rbd_util.go +++ b/pkg/volume/rbd/rbd_util.go @@ -47,13 +47,13 @@ import ( const ( imageWatcherStr = "watcher=" imageSizeStr = "size " - sizeDivStr = " MB in" kubeLockMagic = "kubelet_lock_magic_" // The following three values are used for 30 seconds timeout // while waiting for RBD Watcher to expire. rbdImageWatcherInitDelay = 1 * time.Second rbdImageWatcherFactor = 1.4 rbdImageWatcherSteps = 10 + rbdImageSizeUnitMiB = 1024 * 1024 ) func getDevFromImageAndPool(pool, image string) (string, bool) { @@ -672,8 +672,7 @@ func (util *RBDUtil) ExpandImage(rbdExpander *rbdVolumeExpander, oldSize resourc // rbdInfo runs `rbd info` command to get the current image size in MB. func (util *RBDUtil) rbdInfo(b *rbdMounter) (int, error) { var err error - var output string - var cmd []byte + var output []byte // If we don't have admin id/secret (e.g. attaching), fallback to user id/secret. id := b.adminId @@ -702,9 +701,8 @@ func (util *RBDUtil) rbdInfo(b *rbdMounter) (int, error) { // rbd: error opening image 1234: (2) No such file or directory // klog.V(4).Infof("rbd: info %s using mon %s, pool %s id %s key %s", b.Image, mon, b.Pool, id, secret) - cmd, err = b.exec.Run("rbd", - "info", b.Image, "--pool", b.Pool, "-m", mon, "--id", id, "--key="+secret) - output = string(cmd) + output, err = b.exec.Run("rbd", + "info", b.Image, "--pool", b.Pool, "-m", mon, "--id", id, "--key="+secret, "--format=json") if err, ok := err.(*exec.Error); ok { if err.Err == exec.ErrNotFound { @@ -720,22 +718,20 @@ func (util *RBDUtil) rbdInfo(b *rbdMounter) (int, error) { } if len(output) == 0 { - return 0, fmt.Errorf("can not get image size info %s: %s", b.Image, output) + return 0, fmt.Errorf("can not get image size info %s: %s", b.Image, string(output)) } - // Get the size value string, just between `size ` and ` MB in`, such as `size 1024 MB in 256 objects`. - sizeIndex := strings.Index(output, imageSizeStr) - divIndex := strings.Index(output, sizeDivStr) - if sizeIndex == -1 || divIndex == -1 || divIndex <= sizeIndex+5 { - return 0, fmt.Errorf("can not get image size info %s: %s", b.Image, output) - } - rbdSizeStr := output[sizeIndex+5 : divIndex] - rbdSize, err := strconv.Atoi(rbdSizeStr) - if err != nil { - return 0, fmt.Errorf("can not convert size str: %s to int", rbdSizeStr) - } + return getRbdImageSize(output) +} - return rbdSize, nil +func getRbdImageSize(output []byte) (int, error) { + info := struct { + Size int64 `json:"size"` + }{} + if err := json.Unmarshal(output, &info); err != nil { + return 0, fmt.Errorf("parse rbd info output failed: %s, %v", string(output), err) + } + return int(info.Size / rbdImageSizeUnitMiB), nil } // rbdStatus runs `rbd status` command to check if there is watcher on the image.