From ee9d30a73a74a2e1905eacc561c1b5188b62ca75 Mon Sep 17 00:00:00 2001 From: Zhiteng Huang Date: Tue, 29 Jan 2013 01:12:31 +0800 Subject: [PATCH] Allow volume back-end to report 'infinite' or 'unknown' as capacity For some reason, some volume back-ends cannot report actual capacity that is available or even total capacity (e.g. thin-provisioning), Cinder should allow such capability report and make placement/schedule decision based on these status. In particular, we agree to use 'infinite' to mark unlimited space and 'unknown' to mark unknown/unclear space. Host manager and CapacityFilter are updated accordingly to allow such capacity. For those back-ends report 'infinite' or 'unknown' capacity, CapacityFilter will let them pass to give them a chance to try. Even if failure happened, the retry mechanism should take care of the case. Change-Id: I6871a28745111b1878a606372e6edd664f0ea10c --- cinder/scheduler/filters/capacity_filter.py | 9 ++++++- cinder/scheduler/host_manager.py | 9 ++++++- cinder/tests/scheduler/test_host_filters.py | 22 +++++++++++++++++ cinder/tests/scheduler/test_host_manager.py | 26 +++++++++++++++++++++ 4 files changed, 64 insertions(+), 2 deletions(-) diff --git a/cinder/scheduler/filters/capacity_filter.py b/cinder/scheduler/filters/capacity_filter.py index edd5024b7..fe35033df 100644 --- a/cinder/scheduler/filters/capacity_filter.py +++ b/cinder/scheduler/filters/capacity_filter.py @@ -38,7 +38,14 @@ class CapacityFilter(filters.BaseHostFilter): "volume node info collection broken.")) return False + free_space = host_state.free_capacity_gb + if free_space == 'infinite' or free_space == 'unknown': + # NOTE(zhiteng) for those back-ends cannot report actual + # available capacity, we assume it is able to serve the + # request. Even if it was not, the retry mechanism is + # able to handle the failure by rescheduling + return True reserved = float(host_state.reserved_percentage) / 100 - free = math.floor(host_state.free_capacity_gb * (1 - reserved)) + free = math.floor(free_space * (1 - reserved)) return free >= volume_size diff --git a/cinder/scheduler/host_manager.py b/cinder/scheduler/host_manager.py index 6a76136c9..66926f215 100644 --- a/cinder/scheduler/host_manager.py +++ b/cinder/scheduler/host_manager.py @@ -135,7 +135,14 @@ class HostState(object): def consume_from_volume(self, volume): """Incrementally update host state from an volume""" volume_gb = volume['size'] - self.free_capacity_gb -= volume_gb + if self.free_capacity_gb == 'infinite': + # There's virtually infinite space on back-end + pass + elif self.free_capacity_gb == 'unknown': + # Unable to determine the actual free space on back-end + pass + else: + self.free_capacity_gb -= volume_gb self.updated = timeutils.utcnow() def __repr__(self): diff --git a/cinder/tests/scheduler/test_host_filters.py b/cinder/tests/scheduler/test_host_filters.py index 5bcffd63c..c85a1bf11 100644 --- a/cinder/tests/scheduler/test_host_filters.py +++ b/cinder/tests/scheduler/test_host_filters.py @@ -97,3 +97,25 @@ class HostFiltersTestCase(test.TestCase): 'updated_at': None, 'service': service}) self.assertFalse(filt_cls.host_passes(host, filter_properties)) + + def test_capacity_filter_passes_infinite(self): + self._stub_service_is_up(True) + filt_cls = self.class_map['CapacityFilter']() + filter_properties = {'size': 100} + service = {'disabled': False} + host = fakes.FakeHostState('host1', + {'free_capacity_gb': 'infinite', + 'updated_at': None, + 'service': service}) + self.assertTrue(filt_cls.host_passes(host, filter_properties)) + + def test_capacity_filter_passes_unknown(self): + self._stub_service_is_up(True) + filt_cls = self.class_map['CapacityFilter']() + filter_properties = {'size': 100} + service = {'disabled': False} + host = fakes.FakeHostState('host1', + {'free_capacity_gb': 'unknown', + 'updated_at': None, + 'service': service}) + self.assertTrue(filt_cls.host_passes(host, filter_properties)) diff --git a/cinder/tests/scheduler/test_host_manager.py b/cinder/tests/scheduler/test_host_manager.py index 0d2207ea7..f820b1141 100644 --- a/cinder/tests/scheduler/test_host_manager.py +++ b/cinder/tests/scheduler/test_host_manager.py @@ -174,3 +174,29 @@ class HostStateTestCase(test.TestCase): fake_host.update_from_volume_capability(volume_capability) self.assertEqual(fake_host.free_capacity_gb, 512) + + def test_update_from_volume_infinite_capability(self): + fake_host = host_manager.HostState('host1') + self.assertEqual(fake_host.free_capacity_gb, 0) + + volume_capability = {'total_capacity_gb': 'infinite', + 'free_capacity_gb': 'infinite', + 'reserved_percentage': 0, + 'timestamp': None} + + fake_host.update_from_volume_capability(volume_capability) + self.assertEqual(fake_host.total_capacity_gb, 'infinite') + self.assertEqual(fake_host.free_capacity_gb, 'infinite') + + def test_update_from_volume_unknown_capability(self): + fake_host = host_manager.HostState('host1') + self.assertEqual(fake_host.free_capacity_gb, 0) + + volume_capability = {'total_capacity_gb': 'infinite', + 'free_capacity_gb': 'unknown', + 'reserved_percentage': 0, + 'timestamp': None} + + fake_host.update_from_volume_capability(volume_capability) + self.assertEqual(fake_host.total_capacity_gb, 'infinite') + self.assertEqual(fake_host.free_capacity_gb, 'unknown') -- 2.45.2