RetryFilter checks 'node' as well as 'host'
FilterScheduler and RetryFilter use "(host, node)" instead of "host" to filter candidates. It makes rescheduling on different nodes in the same host possible. Fix bug 1081370 Change-Id: Id51b262de7b47b5f9215463eca5ae07a29109c3f
This commit is contained in:
committed by
Gerrit Code Review
parent
39e5e4853c
commit
f87c2e8334
@@ -146,24 +146,25 @@ class FilterScheduler(driver.Scheduler):
|
||||
|
||||
def _post_select_populate_filter_properties(self, filter_properties,
|
||||
host_state):
|
||||
"""Add additional information to the filter properties after a host has
|
||||
"""Add additional information to the filter properties after a node has
|
||||
been selected by the scheduling process.
|
||||
"""
|
||||
# Add a retry entry for the selected compute host:
|
||||
self._add_retry_host(filter_properties, host_state.host)
|
||||
# Add a retry entry for the selected compute host and node:
|
||||
self._add_retry_host(filter_properties, host_state.host,
|
||||
host_state.nodename)
|
||||
|
||||
self._add_oversubscription_policy(filter_properties, host_state)
|
||||
|
||||
def _add_retry_host(self, filter_properties, host):
|
||||
"""Add a retry entry for the selected compute host. In the event that
|
||||
def _add_retry_host(self, filter_properties, host, node):
|
||||
"""Add a retry entry for the selected compute node. In the event that
|
||||
the request gets re-scheduled, this entry will signal that the given
|
||||
host has already been tried.
|
||||
node has already been tried.
|
||||
"""
|
||||
retry = filter_properties.get('retry', None)
|
||||
if not retry:
|
||||
return
|
||||
hosts = retry['hosts']
|
||||
hosts.append(host)
|
||||
hosts.append((host, node))
|
||||
|
||||
def _add_oversubscription_policy(self, filter_properties, host_state):
|
||||
filter_properties['limits'] = host_state.limits
|
||||
|
||||
@@ -20,12 +20,12 @@ LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class RetryFilter(filters.BaseHostFilter):
|
||||
"""Filter out hosts that have already been attempted for scheduling
|
||||
"""Filter out nodes that have already been attempted for scheduling
|
||||
purposes
|
||||
"""
|
||||
|
||||
def host_passes(self, host_state, filter_properties):
|
||||
"""Skip hosts that have already been attempted"""
|
||||
"""Skip nodes that have already been attempted"""
|
||||
retry = filter_properties.get('retry', None)
|
||||
if not retry:
|
||||
# Re-scheduling is disabled
|
||||
@@ -33,7 +33,7 @@ class RetryFilter(filters.BaseHostFilter):
|
||||
return True
|
||||
|
||||
hosts = retry.get('hosts', [])
|
||||
host = host_state.host
|
||||
host = (host_state.host, host_state.nodename)
|
||||
|
||||
LOG.debug(_("Previously tried hosts: %(hosts)s. (host=%(host)s)") %
|
||||
locals())
|
||||
|
||||
@@ -280,16 +280,17 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
|
||||
retry = dict(num_attempts=1, hosts=[])
|
||||
filter_properties = dict(retry=retry)
|
||||
host = "fakehost"
|
||||
node = "fakenode"
|
||||
|
||||
sched = fakes.FakeFilterScheduler()
|
||||
sched._add_retry_host(filter_properties, host)
|
||||
sched._add_retry_host(filter_properties, host, node)
|
||||
|
||||
hosts = filter_properties['retry']['hosts']
|
||||
self.assertEqual(1, len(hosts))
|
||||
self.assertEqual(host, hosts[0])
|
||||
self.assertEqual((host, node), hosts[0])
|
||||
|
||||
def test_post_select_populate(self):
|
||||
"""Test addition of certain filter props after a host is selected"""
|
||||
"""Test addition of certain filter props after a node is selected"""
|
||||
retry = {'hosts': [], 'num_attempts': 1}
|
||||
filter_properties = {'retry': retry}
|
||||
sched = fakes.FakeFilterScheduler()
|
||||
@@ -299,12 +300,13 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
|
||||
sched._post_select_populate_filter_properties(filter_properties,
|
||||
host_state)
|
||||
|
||||
self.assertEqual('host', filter_properties['retry']['hosts'][0])
|
||||
self.assertEqual(('host', 'node'),
|
||||
filter_properties['retry']['hosts'][0])
|
||||
|
||||
self.assertEqual({'vcpus': 5}, host_state.limits)
|
||||
|
||||
def test_prep_resize_post_populates_retry(self):
|
||||
"""Prep resize should add a 'host' entry to the retry dict"""
|
||||
"""Prep resize should add a ('host', 'node') entry to the retry dict"""
|
||||
sched = fakes.FakeFilterScheduler()
|
||||
|
||||
image = 'image'
|
||||
@@ -335,4 +337,5 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
|
||||
sched.schedule_prep_resize(self.context, image, request_spec,
|
||||
filter_properties, instance, instance_type, reservations)
|
||||
|
||||
self.assertEqual(['host'], filter_properties['retry']['hosts'])
|
||||
self.assertEqual([('host', 'node')],
|
||||
filter_properties['retry']['hosts'])
|
||||
|
||||
@@ -1269,18 +1269,22 @@ class HostFiltersTestCase(test.TestCase):
|
||||
self.assertTrue(filt_cls.host_passes(host, filter_properties))
|
||||
|
||||
def test_retry_filter_pass(self):
|
||||
"""Host not previously tried"""
|
||||
"""Node not previously tried"""
|
||||
filt_cls = self.class_map['RetryFilter']()
|
||||
host = fakes.FakeHostState('host1', 'node1', {})
|
||||
retry = dict(num_attempts=1, hosts=['host2', 'host3'])
|
||||
host = fakes.FakeHostState('host1', 'nodeX', {})
|
||||
retry = dict(num_attempts=2,
|
||||
hosts=[('host1', 'node1'), # same host, different node
|
||||
('host2', 'node2'), # different host and node
|
||||
])
|
||||
filter_properties = dict(retry=retry)
|
||||
self.assertTrue(filt_cls.host_passes(host, filter_properties))
|
||||
|
||||
def test_retry_filter_fail(self):
|
||||
"""Host was already tried"""
|
||||
"""Node was already tried"""
|
||||
filt_cls = self.class_map['RetryFilter']()
|
||||
host = fakes.FakeHostState('host1', 'node1', {})
|
||||
retry = dict(num_attempts=1, hosts=['host3', 'host1'])
|
||||
retry = dict(num_attempts=1,
|
||||
hosts=[('host1', 'node1')])
|
||||
filter_properties = dict(retry=retry)
|
||||
self.assertFalse(filt_cls.host_passes(host, filter_properties))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user