summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Behrens <cbehrens@codestud.com>2012-12-07 23:09:45 +0000
committerChris Behrens <cbehrens@codestud.com>2012-12-07 23:17:28 +0000
commit836ee3f4589f3ee58939a22cedc72e1163497f3f (patch)
tree5e9eba320a9baee9abe13d077c4d91a8fb2d5536
parent86cc905734f81c5363c1dc86ea2bba662bb18892 (diff)
downloadnova-836ee3f4589f3ee58939a22cedc72e1163497f3f.tar.gz
nova-836ee3f4589f3ee58939a22cedc72e1163497f3f.tar.xz
nova-836ee3f4589f3ee58939a22cedc72e1163497f3f.zip
Make ignore_hosts and force_hosts work again
Fixes bug 1087807 A recent refactor of scheduling filters and weights broke the ignore_hosts and force_hosts functionality. The refactored code would have only worked if a list of host names (strings) were passed in to host_manager's get_filtered_hosts(). Unfortunately that's what the unit tests tested, but the real caller (filter_scheduler) actually passes a list of HostState class instances. Unit tests are fixed to pass HostStates and the offending code in the host_manager has been fixed. Change-Id: I54a3385da7c095e8ddf26b7536d46a9ee4072a58
-rw-r--r--nova/scheduler/host_manager.py50
-rw-r--r--nova/tests/scheduler/test_host_manager.py169
2 files changed, 103 insertions, 116 deletions
diff --git a/nova/scheduler/host_manager.py b/nova/scheduler/host_manager.py
index 58a16b109..0c64d7aa2 100644
--- a/nova/scheduler/host_manager.py
+++ b/nova/scheduler/host_manager.py
@@ -294,30 +294,44 @@ class HostManager(object):
def get_filtered_hosts(self, hosts, filter_properties,
filter_class_names=None):
"""Filter hosts and return only ones passing all filters"""
- filter_classes = self._choose_host_filters(filter_class_names)
- hosts = set(hosts)
- ignore_hosts = set(filter_properties.get('ignore_hosts', []))
- ignore_hosts = hosts & ignore_hosts
- if ignore_hosts:
- ignored_hosts = ', '.join(ignore_hosts)
- msg = _('Host filter ignoring hosts: %(ignored_hosts)s')
+ def _strip_ignore_hosts(host_map, hosts_to_ignore):
+ ignored_hosts = []
+ for host in hosts_to_ignore:
+ if host in host_map:
+ del host_map[host]
+ ignored_hosts.append(host)
+ ignored_hosts_str = ', '.join(ignored_hosts)
+ msg = _('Host filter ignoring hosts: %(ignored_hosts_str)s')
LOG.debug(msg, locals())
- hosts = hosts - ignore_hosts
- force_hosts = set(filter_properties.get('force_hosts', []))
- if force_hosts:
- matching_force_hosts = hosts & force_hosts
- if not matching_force_hosts:
- forced_hosts = ', '.join(force_hosts)
+ def _match_forced_hosts(host_map, hosts_to_force):
+ for host in host_map.keys():
+ if host not in hosts_to_force:
+ del host_map[host]
+ if not host_map:
+ forced_hosts_str = ', '.join(hosts_to_force)
msg = _("No hosts matched due to not matching 'force_hosts'"
- "value of '%(forced_hosts)s'")
+ "value of '%(forced_hosts_str)s'")
LOG.debug(msg, locals())
- return []
- forced_hosts = ', '.join(matching_force_hosts)
- msg = _('Host filter forcing available hosts to %(forced_hosts)s')
+ return
+ forced_hosts_str = ', '.join(host_map.iterkeys())
+ msg = _('Host filter forcing available hosts to '
+ '%(forced_hosts_str)s')
LOG.debug(msg, locals())
- hosts = matching_force_hosts
+
+ filter_classes = self._choose_host_filters(filter_class_names)
+ ignore_hosts = filter_properties.get('ignore_hosts', [])
+ force_hosts = filter_properties.get('force_hosts', [])
+ if ignore_hosts or force_hosts:
+ name_to_cls_map = dict([(x.host, x) for x in hosts])
+ if ignore_hosts:
+ _strip_ignore_hosts(name_to_cls_map, ignore_hosts)
+ if force_hosts:
+ _match_forced_hosts(name_to_cls_map, force_hosts)
+ if not name_to_cls_map:
+ return []
+ hosts = name_to_cls_map.itervalues()
return self.filter_handler.get_filtered_objects(filter_classes,
hosts, filter_properties)
diff --git a/nova/tests/scheduler/test_host_manager.py b/nova/tests/scheduler/test_host_manager.py
index d12f1dea5..3463b4aff 100644
--- a/nova/tests/scheduler/test_host_manager.py
+++ b/nova/tests/scheduler/test_host_manager.py
@@ -15,26 +15,27 @@
"""
Tests For HostManager
"""
-
+import sys
from nova.compute import task_states
from nova.compute import vm_states
from nova import db
from nova import exception
from nova.openstack.common import timeutils
+from nova.scheduler import filters
from nova.scheduler import host_manager
from nova import test
from nova.tests import matchers
from nova.tests.scheduler import fakes
-class ComputeFilterClass1(object):
- def host_passes(self, *args, **kwargs):
+class FakeFilterClass1(filters.BaseHostFilter):
+ def host_passes(self, host_state, filter_properties):
pass
-class ComputeFilterClass2(object):
- def host_passes(self, *args, **kwargs):
+class FakeFilterClass2(filters.BaseHostFilter):
+ def host_passes(self, host_state, filter_properties):
pass
@@ -44,164 +45,136 @@ class HostManagerTestCase(test.TestCase):
def setUp(self):
super(HostManagerTestCase, self).setUp()
self.host_manager = host_manager.HostManager()
+ self.fake_hosts = [host_manager.HostState('fake_host%s' % x,
+ 'fake-node') for x in xrange(1, 5)]
def tearDown(self):
timeutils.clear_time_override()
super(HostManagerTestCase, self).tearDown()
def test_choose_host_filters_not_found(self):
- self.flags(scheduler_default_filters='ComputeFilterClass3')
- self.host_manager.filter_classes = [ComputeFilterClass1,
- ComputeFilterClass2]
+ self.flags(scheduler_default_filters='FakeFilterClass3')
+ self.host_manager.filter_classes = [FakeFilterClass1,
+ FakeFilterClass2]
self.assertRaises(exception.SchedulerHostFilterNotFound,
self.host_manager._choose_host_filters, None)
def test_choose_host_filters(self):
- self.flags(scheduler_default_filters=['ComputeFilterClass2'])
- self.host_manager.filter_classes = [ComputeFilterClass1,
- ComputeFilterClass2]
+ self.flags(scheduler_default_filters=['FakeFilterClass2'])
+ self.host_manager.filter_classes = [FakeFilterClass1,
+ FakeFilterClass2]
# Test we returns 1 correct function
filter_classes = self.host_manager._choose_host_filters(None)
self.assertEqual(len(filter_classes), 1)
- self.assertEqual(filter_classes[0].__name__, 'ComputeFilterClass2')
+ self.assertEqual(filter_classes[0].__name__, 'FakeFilterClass2')
+
+ def _mock_get_filtered_hosts(self, info, specified_filters=None):
+ self.mox.StubOutWithMock(self.host_manager, '_choose_host_filters')
+
+ info['got_objs'] = []
+ info['got_fprops'] = []
+
+ def fake_filter_one(_self, obj, filter_props):
+ info['got_objs'].append(obj)
+ info['got_fprops'].append(filter_props)
+ return True
+
+ self.stubs.Set(FakeFilterClass1, '_filter_one', fake_filter_one)
+ self.host_manager._choose_host_filters(specified_filters).AndReturn(
+ [FakeFilterClass1])
+
+ def _verify_result(self, info, result):
+ for x in info['got_fprops']:
+ self.assertEqual(x, info['expected_fprops'])
+ self.assertEqual(set(info['expected_objs']), set(info['got_objs']))
+ self.assertEqual(set(result), set(info['got_objs']))
def test_get_filtered_hosts(self):
- fake_hosts = ['fake_host1', 'fake_host2', 'fake_host1',
- 'fake_host1']
- fake_classes = 'fake_classes'
fake_properties = {'moo': 1, 'cow': 2}
- expected_hosts = set(fake_hosts)
- fake_result = 'fake_result'
- self.mox.StubOutWithMock(self.host_manager, '_choose_host_filters')
- self.mox.StubOutWithMock(self.host_manager.filter_handler,
- 'get_filtered_objects')
+ info = {'expected_objs': self.fake_hosts,
+ 'expected_fprops': fake_properties}
- self.host_manager._choose_host_filters(None).AndReturn(fake_classes)
- self.host_manager.filter_handler.get_filtered_objects(fake_classes,
- expected_hosts, fake_properties).AndReturn(fake_result)
+ self._mock_get_filtered_hosts(info)
self.mox.ReplayAll()
-
- result = self.host_manager. get_filtered_hosts(fake_hosts,
+ result = self.host_manager.get_filtered_hosts(self.fake_hosts,
fake_properties)
- self.assertEqual(result, fake_result)
+ self._verify_result(info, result)
def test_get_filtered_hosts_with_specificed_filters(self):
- fake_hosts = ['fake_host1', 'fake_host2', 'fake_host1',
- 'fake_host1']
- fake_classes = 'fake_classes'
fake_properties = {'moo': 1, 'cow': 2}
- fake_filters = 'fake_filters'
- expected_hosts = set(fake_hosts)
- fake_result = 'fake_result'
- self.mox.StubOutWithMock(self.host_manager, '_choose_host_filters')
- self.mox.StubOutWithMock(self.host_manager.filter_handler,
- 'get_filtered_objects')
-
- self.host_manager._choose_host_filters(fake_filters).AndReturn(
- fake_classes)
- self.host_manager.filter_handler.get_filtered_objects(fake_classes,
- expected_hosts, fake_properties).AndReturn(fake_result)
+ specified_filters = ['FakeFilterClass1', 'FakeFilterClass2']
+ info = {'expected_objs': self.fake_hosts,
+ 'expected_fprops': fake_properties}
+ self._mock_get_filtered_hosts(info, specified_filters)
self.mox.ReplayAll()
- result = self.host_manager.get_filtered_hosts(fake_hosts,
- fake_properties, filter_class_names=fake_filters)
- self.assertEqual(result, fake_result)
+ result = self.host_manager.get_filtered_hosts(self.fake_hosts,
+ fake_properties, filter_class_names=specified_filters)
+ self._verify_result(info, result)
def test_get_filtered_hosts_with_ignore(self):
- fake_hosts = ['fake_host1', 'fake_host2', 'fake_host1',
- 'fake_host1', 'fake_host3', 'fake_host4']
- fake_classes = 'fake_classes'
fake_properties = {'ignore_hosts': ['fake_host1', 'fake_host3',
'fake_host5']}
- expected_hosts = set(['fake_host2', 'fake_host4'])
- fake_result = 'fake_result'
-
- self.mox.StubOutWithMock(self.host_manager, '_choose_host_filters')
- self.mox.StubOutWithMock(self.host_manager.filter_handler,
- 'get_filtered_objects')
- self.host_manager._choose_host_filters(None).AndReturn(fake_classes)
- self.host_manager.filter_handler.get_filtered_objects(fake_classes,
- expected_hosts, fake_properties).AndReturn(fake_result)
+ # [1] and [3] are host2 and host4
+ info = {'expected_objs': [self.fake_hosts[1], self.fake_hosts[3]],
+ 'expected_fprops': fake_properties}
+ self._mock_get_filtered_hosts(info)
self.mox.ReplayAll()
- result = self.host_manager.get_filtered_hosts(fake_hosts,
+ result = self.host_manager.get_filtered_hosts(self.fake_hosts,
fake_properties)
- self.assertEqual(result, fake_result)
+ self._verify_result(info, result)
def test_get_filtered_hosts_with_force_hosts(self):
- fake_hosts = ['fake_host1', 'fake_host2', 'fake_host1',
- 'fake_host1', 'fake_host3', 'fake_host4']
- fake_classes = 'fake_classes'
fake_properties = {'force_hosts': ['fake_host1', 'fake_host3',
'fake_host5']}
- expected_hosts = set(['fake_host1', 'fake_host3'])
- fake_result = 'fake_result'
-
- self.mox.StubOutWithMock(self.host_manager, '_choose_host_filters')
- self.mox.StubOutWithMock(self.host_manager.filter_handler,
- 'get_filtered_objects')
- self.host_manager._choose_host_filters(None).AndReturn(fake_classes)
- self.host_manager.filter_handler.get_filtered_objects(fake_classes,
- expected_hosts, fake_properties).AndReturn(fake_result)
+ # [0] and [2] are host1 and host3
+ info = {'expected_objs': [self.fake_hosts[0], self.fake_hosts[2]],
+ 'expected_fprops': fake_properties}
+ self._mock_get_filtered_hosts(info)
self.mox.ReplayAll()
- result = self.host_manager.get_filtered_hosts(fake_hosts,
+ result = self.host_manager.get_filtered_hosts(self.fake_hosts,
fake_properties)
- self.assertEqual(result, fake_result)
+ self._verify_result(info, result)
def test_get_filtered_hosts_with_no_matching_force_hosts(self):
- fake_hosts = ['fake_host1', 'fake_host2', 'fake_host1',
- 'fake_host1', 'fake_host3', 'fake_host4']
- fake_classes = 'fake_classes'
fake_properties = {'force_hosts': ['fake_host5', 'fake_host6']}
- expected_result = []
- self.mox.StubOutWithMock(self.host_manager, '_choose_host_filters')
- # Make sure this is not called.
- self.mox.StubOutWithMock(self.host_manager.filter_handler,
- 'get_filtered_objects')
-
- self.host_manager._choose_host_filters(None).AndReturn(fake_classes)
+ info = {'expected_objs': [],
+ 'expected_fprops': fake_properties}
+ self._mock_get_filtered_hosts(info)
self.mox.ReplayAll()
- result = self.host_manager.get_filtered_hosts(fake_hosts,
+ result = self.host_manager.get_filtered_hosts(self.fake_hosts,
fake_properties)
- self.assertEqual(result, expected_result)
+ self._verify_result(info, result)
def test_get_filtered_hosts_with_ignore_and_force(self):
"""Ensure ignore_hosts processed before force_hosts in host filters"""
- fake_hosts = ['fake_host1', 'fake_host2', 'fake_host1',
- 'fake_host1', 'fake_host3', 'fake_host4']
- fake_classes = 'fake_classes'
fake_properties = {'force_hosts': ['fake_host3', 'fake_host1'],
'ignore_hosts': ['fake_host1']}
- expected_hosts = set(['fake_host3'])
- fake_result = 'fake_result'
-
- self.mox.StubOutWithMock(self.host_manager, '_choose_host_filters')
- # Make sure this is not called.
- self.mox.StubOutWithMock(self.host_manager.filter_handler,
- 'get_filtered_objects')
- self.host_manager.filter_handler.get_filtered_objects(fake_classes,
- expected_hosts, fake_properties).AndReturn(fake_result)
- self.host_manager._choose_host_filters(None).AndReturn(fake_classes)
+ # only fake_host3 should be left.
+ info = {'expected_objs': [self.fake_hosts[2]],
+ 'expected_fprops': fake_properties}
+ self._mock_get_filtered_hosts(info)
self.mox.ReplayAll()
- result = self.host_manager.get_filtered_hosts(fake_hosts,
+ result = self.host_manager.get_filtered_hosts(self.fake_hosts,
fake_properties)
- self.assertEqual(result, fake_result)
+ self._verify_result(info, result)
def test_update_service_capabilities(self):
service_states = self.host_manager.service_states