diff --git a/cinder/tests/unit/volume/drivers/test_rbd.py b/cinder/tests/unit/volume/drivers/test_rbd.py index e33bad69d19..7e6b954f1e6 100644 --- a/cinder/tests/unit/volume/drivers/test_rbd.py +++ b/cinder/tests/unit/volume/drivers/test_rbd.py @@ -1759,6 +1759,51 @@ class RBDTestCase(test.TestCase): ]) self.assertEqual((free_capacity, total_capacity), result) + @ddt.data( + # Normal case, no quota and dynamic total + {'free_capacity': 27.0, 'total_capacity': 28.44}, + # No quota and static total + {'dynamic_total': False, + 'free_capacity': 27.0, 'total_capacity': 59.96}, + # Quota and dynamic total + {'quota_max_bytes': 3221225472, 'max_avail': 1073741824, + 'free_capacity': 1, 'total_capacity': 2.44}, + # Quota and static total + {'quota_max_bytes': 3221225472, 'max_avail': 1073741824, + 'dynamic_total': False, + 'free_capacity': 1, 'total_capacity': 3.00}, + # Quota and dynamic total when free would be negative + {'quota_max_bytes': 1073741824, + 'free_capacity': 0, 'total_capacity': 1.44}, + ) + @ddt.unpack + @common_mocks + def test_get_pool_nautilus(self, free_capacity, total_capacity, + max_avail=28987613184, quota_max_bytes=0, + dynamic_total=True): + client = self.mock_client.return_value + client.__enter__.return_value = client + client.cluster.mon_command.side_effect = [ + (0, '{"stats":{"total_bytes":64385286144,' + '"total_used_bytes":3289628672,"total_avail_bytes":61095657472},' + '"pools":[{"name":"rbd","id":2,"stats":{"kb_used":1510197,' + '"stored":1546440971,"bytes_used":4639322913,"max_avail":%s,' + '"objects":412}},{"name":"volumes","id":3,"stats":{"kb_used":0,' + '"bytes_used":0,"max_avail":28987613184,"objects":0}}]}\n' % + max_avail, ''), + (0, '{"pool_name":"volumes","pool_id":4,"quota_max_objects":0,' + '"quota_max_bytes":%s}\n' % quota_max_bytes, ''), + ] + with mock.patch.object(self.driver.configuration, 'safe_get', + return_value=dynamic_total): + result = self.driver._get_pool_stats() + client.cluster.mon_command.assert_has_calls([ + mock.call('{"prefix":"df", "format":"json"}', b''), + mock.call('{"prefix":"osd pool get-quota", "pool": "rbd",' + ' "format":"json"}', b''), + ]) + self.assertEqual((free_capacity, total_capacity), result) + @common_mocks def test_get_pool_bytes(self): """Test for mon_commands returning bytes instead of strings.""" diff --git a/cinder/volume/drivers/rbd.py b/cinder/volume/drivers/rbd.py index 16a484536f0..81b436a1e78 100644 --- a/cinder/volume/drivers/rbd.py +++ b/cinder/volume/drivers/rbd.py @@ -642,12 +642,15 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD, total_capacity: float free_capacity: float + + # In Nautilus bytes_used was renamed to stored + bytes_used = pool_stats.get('stored', pool_stats['bytes_used']) quota_outbuf = encodeutils.safe_decode(quota_outbuf) bytes_quota = json.loads(quota_outbuf)['quota_max_bytes'] # With quota the total is the quota limit and free is quota - used if bytes_quota: total_capacity = bytes_quota - free_capacity = max(min(total_capacity - pool_stats['bytes_used'], + free_capacity = max(min(total_capacity - bytes_used, pool_stats['max_avail']), 0) # Without quota free is pools max available and total is global size @@ -657,7 +660,7 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD, # If we want dynamic total capacity (default behavior) if self.configuration.safe_get('report_dynamic_total_capacity'): - total_capacity = free_capacity + pool_stats['bytes_used'] + total_capacity = free_capacity + bytes_used free_capacity = round((float(free_capacity) / units.Gi), 2) total_capacity = round((float(total_capacity) / units.Gi), 2) diff --git a/releasenotes/notes/rbd-total_capacity-60f10b45e3a8c8ea.yaml b/releasenotes/notes/rbd-total_capacity-60f10b45e3a8c8ea.yaml new file mode 100644 index 00000000000..1efa650974c --- /dev/null +++ b/releasenotes/notes/rbd-total_capacity-60f10b45e3a8c8ea.yaml @@ -0,0 +1,8 @@ +--- +fixes: + - | + RBD driver `bug #1960206 + `_: Fixed + ``total_capacity`` reported by the driver to the scheduler on Ceph clusters + that have renamed the ``bytes_used`` field to ``stored``. (e.g., `Nautilus + `_).