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):
'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)
# -*- coding: utf-8 -*-
-# pylint: disable=too-many-arguments
+# pylint: disable=too-many-arguments,too-many-locals
from __future__ import absolute_import
import math
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()
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():
})
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()