diff --git a/nova/scheduler/host_manager.py b/nova/scheduler/host_manager.py index f2b30811760..2e9aac71ad7 100644 --- a/nova/scheduler/host_manager.py +++ b/nova/scheduler/host_manager.py @@ -505,10 +505,33 @@ def _match_forced_nodes(host_map, nodes_to_force): "'force_nodes' value of '%s'") LOG.info(msg % forced_nodes_str) + def _get_hosts_matching_request(hosts, requested_destination): + (host, node) = (requested_destination.host, + requested_destination.node) + requested_nodes = [x for x in hosts + if x.host == host and x.nodename == node] + if requested_nodes: + LOG.info(_LI('Host filter only checking host %(host)s and ' + 'node %(node)s') % {'host': host, 'node': node}) + else: + # NOTE(sbauza): The API level should prevent the user from + # providing a wrong destination but let's make sure a wrong + # destination doesn't trample the scheduler still. + LOG.info(_LI('No hosts matched due to not matching requested ' + 'destination (%(host)s, %(node)s)' + ) % {'host': host, 'node': node}) + return iter(requested_nodes) + ignore_hosts = spec_obj.ignore_hosts or [] force_hosts = spec_obj.force_hosts or [] force_nodes = spec_obj.force_nodes or [] + requested_node = spec_obj.requested_destination + if requested_node is not None: + # NOTE(sbauza): Reduce a potentially long set of hosts as much as + # possible to any requested destination nodes before passing the + # list to the filters + hosts = _get_hosts_matching_request(hosts, requested_node) if ignore_hosts or force_hosts or force_nodes: # NOTE(deva): we can't assume "host" is unique because # one host may have many nodes. diff --git a/nova/tests/unit/scheduler/test_host_manager.py b/nova/tests/unit/scheduler/test_host_manager.py index 75417fccc71..35b8cce8943 100644 --- a/nova/tests/unit/scheduler/test_host_manager.py +++ b/nova/tests/unit/scheduler/test_host_manager.py @@ -222,6 +222,40 @@ def test_get_filtered_hosts(self): fake_properties) self._verify_result(info, result) + def test_get_filtered_hosts_with_requested_destination(self): + dest = objects.Destination(host='fake_host1', node='fake-node') + fake_properties = objects.RequestSpec(requested_destination=dest, + ignore_hosts=[], + instance_uuid='fake-uuid1', + force_hosts=[], + force_nodes=[]) + + info = {'expected_objs': [self.fake_hosts[0]], + 'expected_fprops': fake_properties} + + self._mock_get_filtered_hosts(info) + + result = self.host_manager.get_filtered_hosts(self.fake_hosts, + fake_properties) + self._verify_result(info, result) + + def test_get_filtered_hosts_with_wrong_requested_destination(self): + dest = objects.Destination(host='dummy', node='fake-node') + fake_properties = objects.RequestSpec(requested_destination=dest, + ignore_hosts=[], + instance_uuid='fake-uuid1', + force_hosts=[], + force_nodes=[]) + + info = {'expected_objs': [], + 'expected_fprops': fake_properties} + + self._mock_get_filtered_hosts(info) + + result = self.host_manager.get_filtered_hosts(self.fake_hosts, + fake_properties) + self._verify_result(info, result) + def test_get_filtered_hosts_with_ignore(self): fake_properties = objects.RequestSpec( instance_uuid=uuids.instance,