From: Ricardo Dias Date: Wed, 28 Mar 2018 16:06:02 +0000 (+0100) Subject: mgr/dashboard: rbd: image disk usage implementation X-Git-Tag: v13.1.0~234^2~25 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=fa7cac815828d26864a36588432c68e5085abbcd;p=ceph.git mgr/dashboard: rbd: image disk usage implementation Signed-off-by: Ricardo Dias --- diff --git a/qa/tasks/mgr/dashboard/test_rbd.py b/qa/tasks/mgr/dashboard/test_rbd.py index 4353e984f07..b0fd8b84a1f 100644 --- a/qa/tasks/mgr/dashboard/test_rbd.py +++ b/qa/tasks/mgr/dashboard/test_rbd.py @@ -85,6 +85,7 @@ class RbdTest(DashboardTestCase): self.assertIn('parent', img) self.assertIn('data_pool', img) self.assertIn('snapshots', img) + self.assertIn('disk_usage', img) for k, v in kwargs.items(): if isinstance(v, list): @@ -227,3 +228,16 @@ class RbdTest(DashboardTestCase): 'fast-diff', 'layering', 'object-map']) self._rbd_cmd(['rm', 'rbd_iscsi/img1_clone']) + + def test_disk_usage(self): + self._rbd_cmd(['bench', '--io-type', 'write', '--io-total', '50M', 'rbd/img2']) + self._rbd_cmd(['snap', 'create', 'rbd/img2@snap1']) + self._rbd_cmd(['bench', '--io-type', 'write', '--io-total', '20M', 'rbd/img2']) + self._rbd_cmd(['snap', 'create', 'rbd/img2@snap2']) + self._rbd_cmd(['bench', '--io-type', 'write', '--io-total', '10M', 'rbd/img2']) + self._rbd_cmd(['snap', 'create', 'rbd/img2@snap3']) + self._rbd_cmd(['bench', '--io-type', 'write', '--io-total', '5M', 'rbd/img2']) + img = self._get('/api/rbd/rbd/img2') + self.assertStatus(200) + self._validate_image(img, name='img2', size=2147483648, + total_disk_usage=268435456, disk_usage=67108864) diff --git a/src/pybind/mgr/dashboard/controllers/rbd.py b/src/pybind/mgr/dashboard/controllers/rbd.py index 5a77faf9a3f..f05cda281f5 100644 --- a/src/pybind/mgr/dashboard/controllers/rbd.py +++ b/src/pybind/mgr/dashboard/controllers/rbd.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# pylint: disable=too-many-arguments +# pylint: disable=too-many-arguments,too-many-locals from __future__ import absolute_import import math @@ -63,6 +63,29 @@ class Rbd(RESTController): res = key | res return res + @classmethod + def _rbd_disk_usage(cls, image, snaps): + class DUCallback(object): + def __init__(self): + self.used_size = 0 + + def __call__(self, offset, length, exists): + if exists: + self.used_size += length + + snap_map = {} + prev_snap = None + total_used_size = 0 + for _, size, name in snaps: + image.set_snap(name) + du_callb = DUCallback() + image.diff_iterate(0, size, prev_snap, du_callb, whole_object=True) + snap_map[name] = du_callb.used_size + total_used_size += du_callb.used_size + prev_snap = name + + return total_used_size, snap_map + def _rbd_image(self, ioctx, pool_name, image_name): img = rbd.Image(ioctx, image_name) stat = img.stat() @@ -103,6 +126,7 @@ class Rbd(RESTController): for snap in img.list_snaps(): snap['timestamp'] = "{}Z".format(img.get_snap_timestamp(snap['id']).isoformat()) snap['is_protected'] = img.is_protected_snap(snap['name']) + snap['used_bytes'] = None snap['children'] = [] img.set_snap(snap['name']) for child_pool_name, child_image_name in img.list_children(): @@ -112,6 +136,25 @@ class Rbd(RESTController): }) stat['snapshots'].append(snap) + # disk usage + if 'fast-diff' in stat['features_name']: + snaps = [(s['id'], s['size'], s['name']) for s in stat['snapshots']] + snaps.sort(key=lambda s: s[0]) + snaps += [(snaps[-1][0]+1 if snaps else 0, stat['size'], None)] + total_used_bytes, snaps_used_bytes = self._rbd_disk_usage(img, snaps) + stat['total_disk_usage'] = total_used_bytes + for snap, used_bytes in snaps_used_bytes.items(): + if snap is None: + stat['disk_usage'] = used_bytes + continue + for ss in stat['snapshots']: + if ss['name'] == snap: + ss['disk_usage'] = used_bytes + break + else: + stat['total_disk_usage'] = None + stat['disk_usage'] = None + return stat @ViewCache()