diff --git a/nova/scheduler/utils.py b/nova/scheduler/utils.py index 601f35d3f1f2..16008f4c82ab 100644 --- a/nova/scheduler/utils.py +++ b/nova/scheduler/utils.py @@ -343,6 +343,12 @@ def resources_from_request_spec(spec_obj): if 'force_nodes' in spec_obj and spec_obj.force_nodes: res_req._limit = None + # Don't limit allocation candidates when using affinity/anti-affinity. + if ('scheduler_hints' in spec_obj and any( + key in ['group', 'same_host', 'different_host'] + for key in spec_obj.scheduler_hints)): + res_req._limit = None + return res_req diff --git a/nova/tests/unit/scheduler/test_utils.py b/nova/tests/unit/scheduler/test_utils.py index 7a09731131cf..e92dd111cd4e 100644 --- a/nova/tests/unit/scheduler/test_utils.py +++ b/nova/tests/unit/scheduler/test_utils.py @@ -10,6 +10,7 @@ # License for the specific language governing permissions and limitations # under the License. +import ddt import mock from nova.api.openstack.placement import lib as plib @@ -23,6 +24,7 @@ from nova.tests.unit import fake_instance from nova.tests import uuidsentinel as uuids +@ddt.ddt class TestUtils(test.NoDBTestCase): def setUp(self): @@ -35,6 +37,7 @@ class TestUtils(test.NoDBTestCase): self.assertEqual(set(ex_by_id), set(ob_by_id)) for ident in ex_by_id: self.assertEqual(vars(ex_by_id[ident]), vars(ob_by_id[ident])) + self.assertEqual(expected._limit, observed._limit) def _test_resources_from_request_spec(self, flavor, expected): fake_spec = objects.RequestSpec(flavor=flavor) @@ -299,6 +302,38 @@ class TestUtils(test.NoDBTestCase): resources = utils.resources_from_request_spec(fake_spec) self.assertEqual(expected._limit, resources._limit) + @ddt.data( + # Test single hint that we are checking for. + {'group': [uuids.fake]}, + # Test hint we care about and some other random hint. + {'same_host': [uuids.fake], 'fake-hint': ['fake-value']}, + # Test multiple hints we are checking for. + {'same_host': [uuids.server1], 'different_host': [uuids.server2]}) + def test_resources_from_request_spec_no_limit_based_on_hint(self, hints): + """Tests that there is no limit applied to the + GET /allocation_candidates query string if a given scheduler hint + is in the request spec. + """ + flavor = objects.Flavor(vcpus=1, + memory_mb=1024, + root_gb=15, + ephemeral_gb=0, + swap=0) + fake_spec = objects.RequestSpec( + flavor=flavor, scheduler_hints=hints) + expected = utils.ResourceRequest() + expected._rg_by_id[None] = plib.RequestGroup( + use_same_provider=False, + resources={ + 'VCPU': 1, + 'MEMORY_MB': 1024, + 'DISK_GB': 15, + }, + ) + expected._limit = None + resources = utils.resources_from_request_spec(fake_spec) + self.assertResourceRequestsEqual(expected, resources) + @mock.patch('nova.compute.utils.is_volume_backed_instance', return_value=False) def test_resources_from_flavor_no_bfv(self, mock_is_bfv):