]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Allow volume back-end to report 'infinite' or 'unknown' as capacity
authorZhiteng Huang <zhiteng.huang@intel.com>
Mon, 28 Jan 2013 17:12:31 +0000 (01:12 +0800)
committerZhiteng Huang <zhiteng.huang@intel.com>
Tue, 29 Jan 2013 05:08:40 +0000 (13:08 +0800)
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
cinder/scheduler/host_manager.py
cinder/tests/scheduler/test_host_filters.py
cinder/tests/scheduler/test_host_manager.py

index edd5024b74979a6f8520b41406e5d8a5274ff7ba..fe35033df1df8ce4952b15a2d2ef02d56d444fb9 100644 (file)
@@ -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
index 6a76136c9318cc3423577201d9e32e92e25ed3a4..66926f215f4322ea3c0aaef1346fe6035b44e4d5 100644 (file)
@@ -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):
index 5bcffd63c082e7bce8bddfa8eeec4609bcba547f..c85a1bf11e964fec0588ad4a484e79338f5ac860 100644 (file)
@@ -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))
index 0d2207ea71ba1f029b855118573ff0c67534cbaa..f820b11416a6efa1618dc99a1fa850f296c54481 100644 (file)
@@ -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')