From ac219d5dd93c5c637336a9c79389fc260af65d36 Mon Sep 17 00:00:00 2001 From: wuyuting Date: Fri, 20 Mar 2015 18:41:11 +0800 Subject: [PATCH] Rbd update volume stats in wrong way Cinder volume uses a RADOS pool to store volumes and update storage stats periodically. However, rbd driver reports the whole cluster stats but not the pool's. This is wrong. The right way is to report the pool stats but not the whole cluster. Change-Id: Ie18324ebd8b85f7b63dc034ba20857ae9e470804 Closes-Bug: #1434441 --- cinder/tests/test_rbd.py | 26 ++++++++++++++++---------- cinder/volume/drivers/rbd.py | 17 ++++++++++++++--- 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/cinder/tests/test_rbd.py b/cinder/tests/test_rbd.py index b30735293..fcd3bcc63 100644 --- a/cinder/tests/test_rbd.py +++ b/cinder/tests/test_rbd.py @@ -662,10 +662,14 @@ class RBDTestCase(test.TestCase): client.__enter__.return_value = client client.cluster = mock.Mock() - client.cluster.get_cluster_stats = mock.Mock() - client.cluster.get_cluster_stats.return_value = {'kb': 1024 ** 3, - 'kb_avail': 1024 ** 2} - + client.cluster.mon_command = mock.Mock() + client.cluster.mon_command.return_value = ( + 0, '{"stats":{"total_bytes":64385286144,' + '"total_used_bytes":3289628672,"total_avail_bytes":61095657472},' + '"pools":[{"name":"rbd","id":2,"stats":{"kb_used":1510197,' + '"bytes_used":1546440971,"max_avail":28987613184,"objects":412}},' + '{"name":"volumes","id":3,"stats":{"kb_used":0,"bytes_used":0,' + '"max_avail":28987613184,"objects":0}}]}\n', '') self.driver.configuration.safe_get = mock.Mock() self.driver.configuration.safe_get.return_value = 'RBD' @@ -674,12 +678,13 @@ class RBDTestCase(test.TestCase): vendor_name='Open Source', driver_version=self.driver.VERSION, storage_protocol='ceph', - total_capacity_gb=1024, - free_capacity_gb=1, + total_capacity_gb=27, + free_capacity_gb=26, reserved_percentage=0) actual = self.driver.get_volume_stats(True) - client.cluster.get_cluster_stats.assert_called_once_with() + client.cluster.mon_command.assert_called_once_with( + '{"prefix":"df", "format":"json"}', '') self.assertDictMatch(expected, actual) @common_mocks @@ -688,8 +693,8 @@ class RBDTestCase(test.TestCase): client.__enter__.return_value = client client.cluster = mock.Mock() - client.cluster.get_cluster_stats = mock.Mock() - client.cluster.get_cluster_stats.side_effect = Exception + client.cluster.mon_command = mock.Mock() + client.cluster.mon_command.return_value = (22, '', '') self.driver.configuration.safe_get = mock.Mock() self.driver.configuration.safe_get.return_value = 'RBD' @@ -703,7 +708,8 @@ class RBDTestCase(test.TestCase): reserved_percentage=0) actual = self.driver.get_volume_stats(True) - client.cluster.get_cluster_stats.assert_called_once_with() + client.cluster.mon_command.assert_called_once_with( + '{"prefix":"df", "format":"json"}', '') self.assertDictMatch(expected, actual) @common_mocks diff --git a/cinder/volume/drivers/rbd.py b/cinder/volume/drivers/rbd.py index d9e939b5e..7dae2ec20 100644 --- a/cinder/volume/drivers/rbd.py +++ b/cinder/volume/drivers/rbd.py @@ -371,9 +371,20 @@ class RBDDriver(driver.VolumeDriver): try: with RADOSClient(self) as client: - new_stats = client.cluster.get_cluster_stats() - stats['total_capacity_gb'] = new_stats['kb'] / units.Mi - stats['free_capacity_gb'] = new_stats['kb_avail'] / units.Mi + ret, outbuf, _outs = client.cluster.mon_command( + '{"prefix":"df", "format":"json"}', '') + if ret != 0: + LOG.warning(_LW('Unable to get rados pool stats.')) + else: + outbuf = json.loads(outbuf) + pool_stats = [pool for pool in outbuf['pools'] if + pool['name'] == + self.configuration.rbd_pool][0]['stats'] + stats['free_capacity_gb'] = ( + pool_stats['max_avail'] / units.Gi) + used_capacity_gb = pool_stats['bytes_used'] / units.Gi + stats['total_capacity_gb'] = (stats['free_capacity_gb'] + + used_capacity_gb) except self.rados.Error: # just log and return unknown capacities LOG.exception(_LE('error refreshing volume stats')) -- 2.45.2