diff --git a/nova/scheduler/filter_scheduler.py b/nova/scheduler/filter_scheduler.py index b2920b57c5d..cb91951ec30 100644 --- a/nova/scheduler/filter_scheduler.py +++ b/nova/scheduler/filter_scheduler.py @@ -245,12 +245,14 @@ def _populate_retry(self, filter_properties, instance_properties): request. If maximum retries is exceeded, raise NoValidHost. """ max_attempts = self._max_attempts() - retry = filter_properties.pop('retry', {}) + force_hosts = filter_properties.get('force_hosts', []) + force_nodes = filter_properties.get('force_nodes', []) - if max_attempts == 1: + if max_attempts == 1 or force_hosts or force_nodes: # re-scheduling is disabled. return + retry = filter_properties.pop('retry', {}) # retry is enabled, update attempt count: if retry: retry['num_attempts'] += 1 diff --git a/nova/scheduler/utils.py b/nova/scheduler/utils.py index 316e88c6401..8ef0e04eb85 100644 --- a/nova/scheduler/utils.py +++ b/nova/scheduler/utils.py @@ -121,7 +121,9 @@ def _add_retry_host(filter_properties, host, node): node has already been tried. """ retry = filter_properties.get('retry', None) - if not retry: + force_hosts = filter_properties.get('force_hosts', []) + force_nodes = filter_properties.get('force_nodes', []) + if not retry or force_hosts or force_nodes: return hosts = retry['hosts'] hosts.append([host, node]) diff --git a/nova/tests/scheduler/test_filter_scheduler.py b/nova/tests/scheduler/test_filter_scheduler.py index ac790bd4181..de4bf584eaa 100644 --- a/nova/tests/scheduler/test_filter_scheduler.py +++ b/nova/tests/scheduler/test_filter_scheduler.py @@ -229,6 +229,44 @@ def test_retry_disabled(self): # should not have retry info in the populated filter properties: self.assertFalse("retry" in filter_properties) + def test_retry_force_hosts(self): + # Retry info should not get populated when re-scheduling is off. + self.flags(scheduler_max_attempts=2) + sched = fakes.FakeFilterScheduler() + + instance_properties = {'project_id': '12345', 'os_type': 'Linux'} + request_spec = dict(instance_properties=instance_properties) + filter_properties = dict(force_hosts=['force_host']) + + self.mox.StubOutWithMock(db, 'compute_node_get_all') + db.compute_node_get_all(mox.IgnoreArg()).AndReturn([]) + self.mox.ReplayAll() + + sched._schedule(self.context, request_spec, + filter_properties=filter_properties) + + # should not have retry info in the populated filter properties: + self.assertFalse("retry" in filter_properties) + + def test_retry_force_nodes(self): + # Retry info should not get populated when re-scheduling is off. + self.flags(scheduler_max_attempts=2) + sched = fakes.FakeFilterScheduler() + + instance_properties = {'project_id': '12345', 'os_type': 'Linux'} + request_spec = dict(instance_properties=instance_properties) + filter_properties = dict(force_nodes=['force_node']) + + self.mox.StubOutWithMock(db, 'compute_node_get_all') + db.compute_node_get_all(mox.IgnoreArg()).AndReturn([]) + self.mox.ReplayAll() + + sched._schedule(self.context, request_spec, + filter_properties=filter_properties) + + # should not have retry info in the populated filter properties: + self.assertFalse("retry" in filter_properties) + def test_retry_attempt_one(self): # Test retry logic on initial scheduling attempt. self.flags(scheduler_max_attempts=2) diff --git a/nova/tests/scheduler/test_scheduler_utils.py b/nova/tests/scheduler/test_scheduler_utils.py index ff3e8168bc8..84db590f527 100644 --- a/nova/tests/scheduler/test_scheduler_utils.py +++ b/nova/tests/scheduler/test_scheduler_utils.py @@ -92,9 +92,15 @@ def test_set_vm_state_and_notify_uuid_from_instance_props(self): self._test_set_vm_state_and_notify(request_spec, expected_uuids) def _test_populate_filter_props(self, host_state_obj=True, - with_retry=True): + with_retry=True, + force_hosts=[], + force_nodes=[]): if with_retry: - filter_properties = dict(retry=dict(hosts=[])) + if not force_hosts and not force_nodes: + filter_properties = dict(retry=dict(hosts=[])) + else: + filter_properties = dict(force_hosts=force_hosts, + force_nodes=force_nodes) else: filter_properties = dict() @@ -110,13 +116,13 @@ class host_state(object): scheduler_utils.populate_filter_properties(filter_properties, host_state) - if with_retry: + if with_retry and not force_hosts and not force_nodes: # So we can check for 2 hosts scheduler_utils.populate_filter_properties(filter_properties, host_state) self.assertEqual('fake-limits', filter_properties['limits']) - if with_retry: + if with_retry and not force_hosts and not force_nodes: self.assertEqual([['fake-host', 'fake-node'], ['fake-host', 'fake-node']], filter_properties['retry']['hosts']) @@ -131,3 +137,9 @@ def test_populate_filter_props_host_dict(self): def test_populate_filter_props_no_retry(self): self._test_populate_filter_props(with_retry=False) + + def test_populate_filter_props_force_hosts_no_retry(self): + self._test_populate_filter_props(force_hosts=['force-host']) + + def test_populate_filter_props_force_nodes_no_retry(self): + self._test_populate_filter_props(force_nodes=['force-node'])