]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: rbd: image disk usage implementation
authorRicardo Dias <rdias@suse.com>
Wed, 28 Mar 2018 16:06:02 +0000 (17:06 +0100)
committerRicardo Dias <rdias@suse.com>
Fri, 13 Apr 2018 14:58:47 +0000 (15:58 +0100)
Signed-off-by: Ricardo Dias <rdias@suse.com>
qa/tasks/mgr/dashboard/test_rbd.py
src/pybind/mgr/dashboard/controllers/rbd.py

index 4353e984f0738d150ce728a7669e8a10d64b9ded..b0fd8b84a1fa0bd5460675d8fee82a70bddf7df5 100644 (file)
@@ -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)
index 5a77faf9a3f3e4a67843c0c5286a9b19fc766942..f05cda281f53715ab93536e8c3a00fa906fdad6e 100644 (file)
@@ -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()