Apply scheduler limits to Exact* filters

The DiskFilter, RamFilter and CoreFilter scheduler filters set the
resource limit on the HostState object during filtering. This is
later checked in compute during the claim, and used to enforce
the allocation ratios in a safe manner. The Exact* filters do not
set the resource limits, so scheduler race conditions can result
in multiple bare metal instances claiming a single host.

This change sets the resource limits on the HostState object in
the ExactCoreFilter, ExactDiskFilter and ExactRamFilter, ensuring
that only a single baremetal instance can claim a compute host.

 Conflicts:
	nova/tests/unit/scheduler/filters/test_exact_core_filter.py
	nova/tests/unit/scheduler/filters/test_exact_disk_filter.py
	nova/tests/unit/scheduler/filters/test_exact_ram_filter.py

Change-Id: I31d0331afc4698046a4568935a95f70f30e335dd
Partial-Bug: #1341420
Co-Authored-By: Will Miller <wmiller@cray.com>
(cherry picked from commit 3471cc8b74)
This commit is contained in:
Mark Goddard 2016-01-27 03:49:07 +00:00
parent c5d0d2d0f4
commit 19e7abad96
6 changed files with 25 additions and 2 deletions

View File

@ -48,4 +48,8 @@ class ExactCoreFilter(filters.BaseHostFilter):
'usable_vcpus': usable_vcpus})
return False
# NOTE(mgoddard): Setting the limit ensures that it is enforced in
# compute. This ensures that if multiple instances are scheduled to a
# single host, then all after the first will fail in the claim.
host_state.limits['vcpu'] = host_state.vcpus_total
return True

View File

@ -39,4 +39,8 @@ class ExactDiskFilter(filters.BaseHostFilter):
'usable_disk_mb': host_state.free_disk_mb})
return False
# NOTE(mgoddard): Setting the limit ensures that it is enforced in
# compute. This ensures that if multiple instances are scheduled to a
# single host, then all after the first will fail in the claim.
host_state.limits['disk_gb'] = host_state.total_usable_disk_gb
return True

View File

@ -36,4 +36,8 @@ class ExactRamFilter(filters.BaseHostFilter):
'usable_ram': host_state.free_ram_mb})
return False
# NOTE(mgoddard): Setting the limit ensures that it is enforced in
# compute. This ensures that if multiple instances are scheduled to a
# single host, then all after the first will fail in the claim.
host_state.limits['memory_mb'] = host_state.total_usable_ram_mb
return True

View File

@ -25,11 +25,13 @@ class TestExactCoreFilter(test.NoDBTestCase):
filter_properties = {'instance_type': {'vcpus': 1}}
host = self._get_host({'vcpus_total': 3, 'vcpus_used': 2})
self.assertTrue(self.filt_cls.host_passes(host, filter_properties))
self.assertEqual(host.limits.get('vcpu'), 3)
def test_exact_core_filter_fails(self):
filter_properties = {'instance_type': {'vcpus': 2}}
host = self._get_host({'vcpus_total': 3, 'vcpus_used': 2})
self.assertFalse(self.filt_cls.host_passes(host, filter_properties))
self.assertNotIn('vcpu', host.limits)
def test_exact_core_filter_passes_no_instance_type(self):
filter_properties = {}
@ -40,6 +42,7 @@ class TestExactCoreFilter(test.NoDBTestCase):
filter_properties = {'instance_type': {'vcpus': 1}}
host = self._get_host({})
self.assertFalse(self.filt_cls.host_passes(host, filter_properties))
self.assertNotIn('vcpu', host.limits)
def _get_host(self, host_attributes):
return fakes.FakeHostState('host1', 'node1', host_attributes)

View File

@ -29,8 +29,11 @@ class TestExactDiskFilter(test.NoDBTestCase):
'swap': 1024
}
}
host = self._get_host({'free_disk_mb': 3 * 1024})
disk_gb = 3
host = self._get_host({'free_disk_mb': disk_gb * 1024,
'total_usable_disk_gb': disk_gb})
self.assertTrue(self.filt_cls.host_passes(host, filter_properties))
self.assertEqual(host.limits.get('disk_gb'), disk_gb)
def test_exact_disk_filter_fails(self):
filter_properties = {
@ -42,6 +45,7 @@ class TestExactDiskFilter(test.NoDBTestCase):
}
host = self._get_host({'free_disk_mb': 2 * 1024})
self.assertFalse(self.filt_cls.host_passes(host, filter_properties))
self.assertNotIn('disk_gb', host.limits)
def _get_host(self, host_attributes):
return fakes.FakeHostState('host1', 'node1', host_attributes)

View File

@ -23,13 +23,17 @@ class TestRamFilter(test.NoDBTestCase):
def test_exact_ram_filter_passes(self):
filter_properties = {'instance_type': {'memory_mb': 1024}}
host = self._get_host({'free_ram_mb': 1024})
ram_mb = 1024
host = self._get_host({'free_ram_mb': ram_mb,
'total_usable_ram_mb': ram_mb})
self.assertTrue(self.filt_cls.host_passes(host, filter_properties))
self.assertEqual(host.limits.get('memory_mb'), ram_mb)
def test_exact_ram_filter_fails(self):
filter_properties = {'instance_type': {'memory_mb': 512}}
host = self._get_host({'free_ram_mb': 1024})
self.assertFalse(self.filt_cls.host_passes(host, filter_properties))
self.assertNotIn('memory_mb', host.limits)
def _get_host(self, host_attributes):
return fakes.FakeHostState('host1', 'node1', host_attributes)