Raise NoValidHost if no allocation candidates

Placement took over the role of the CoreFilter, RamFilter and DiskFilter
from the FilterScheduler. Therefore if placement returns no allocation
candidates for a request then scheduling should be stopped as this means
there is not enough VCPU, MEMORY_MB, or DISK_GB available in any compute
node for the request.

Change-Id: If20a20e5cce7ab490998643e32556a1016646b07
Closes-Bug: #1708637
This commit is contained in:
Balazs Gibizer 2017-08-07 15:12:25 +02:00
parent 13f52d443e
commit 6b0ab40e42
3 changed files with 30 additions and 66 deletions

View File

@ -134,13 +134,7 @@ class SchedulerManager(manager.Manager):
"API. This may be a temporary occurrence as compute " "API. This may be a temporary occurrence as compute "
"nodes start up and begin reporting inventory to " "nodes start up and begin reporting inventory to "
"the Placement service.") "the Placement service.")
# TODO(jaypipes): Setting provider_summaries to None triggers raise exception.NoValidHost(reason="")
# the scheduler to load all compute nodes to do scheduling "the
# old way". Really, we should raise NoValidHosts here, but all
# functional tests will fall over if we do that without
# changing the PlacementFixture to load compute node inventory
# into the placement database before starting functional tests.
provider_summaries = None
else: else:
# Build a dict of lists of allocation requests, keyed by # Build a dict of lists of allocation requests, keyed by
# provider UUID, so that when we attempt to claim resources for # provider UUID, so that when we attempt to claim resources for

View File

@ -1612,22 +1612,13 @@ class ServerMovingTests(test.TestCase, integrated_helpers.InstanceHelperMixin):
} }
} }
# NOTE(gibi): This is bug 1708637. Placement returns no allocation resp = self.api.post_server_action(
# candidate and the scheduler falls back to the legacy filtering. As server['id'], resize_req, check_response_status=[400])
# CoreFilter is not enabled the filtering result in hosts selected self.assertEqual(
# without enough VCPU resource resp['badRequest']['message'],
self.api.post_server_action(server['id'], resize_req) "No valid host was found. No valid host found for resize")
server = self._wait_for_state_change(self.api, server, 'VERIFY_RESIZE') server = self.admin_api.get_server(server['id'])
self.assertEqual(dest_hostname, server['OS-EXT-SRV-ATTR:host']) self.assertEqual(source_hostname, server['OS-EXT-SRV-ATTR:host'])
# Note(gibi): After bug 1708637 is fixed the following is expected
# resp = self.api.post_server_action(
# server['id'], resize_req, check_response_status=[400])
# self.assertEqual(
# resp['badRequest']['message'],
# "No valid host was found. No valid host found for resize")
# server = self.admin_api.get_server(server['id'])
# self.assertEqual(source_hostname, server['OS-EXT-SRV-ATTR:host'])
# only the source host shall have usages after the failed resize # only the source host shall have usages after the failed resize
source_usages = self._get_provider_usages(source_rp_uuid) source_usages = self._get_provider_usages(source_rp_uuid)

View File

@ -18,6 +18,7 @@ Tests For Scheduler
""" """
import mock import mock
import oslo_messaging as messaging
import nova.conf import nova.conf
from nova import context from nova import context
@ -127,67 +128,45 @@ class SchedulerManagerTestCase(test.NoDBTestCase):
@mock.patch('nova.scheduler.utils.resources_from_request_spec') @mock.patch('nova.scheduler.utils.resources_from_request_spec')
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.' @mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
'get_allocation_candidates') 'get_allocation_candidates')
def test_select_destination_old_placement(self, mock_get_ac, mock_rfrs): def _test_select_destination(self, get_allocation_candidates_response,
"""Tests that we will pass None for the provider_summaries parameter to mock_get_ac, mock_rfrs):
the scheduler driver select_destinations() method when the scheduler
report client's get_allocation_candidates() returns None, None as it
would if placement service hasn't been upgraded before scheduler.
"""
fake_spec = objects.RequestSpec() fake_spec = objects.RequestSpec()
fake_spec.instance_uuid = uuids.instance fake_spec.instance_uuid = uuids.instance
place_res = (None, None) place_res = get_allocation_candidates_response
mock_get_ac.return_value = place_res mock_get_ac.return_value = place_res
with mock.patch.object(self.manager.driver, 'select_destinations' with mock.patch.object(self.manager.driver, 'select_destinations'
) as select_destinations: ) as select_destinations:
self.manager.select_destinations(None, spec_obj=fake_spec, self.assertRaises(messaging.rpc.dispatcher.ExpectedException,
self.manager.select_destinations, None, spec_obj=fake_spec,
instance_uuids=[fake_spec.instance_uuid]) instance_uuids=[fake_spec.instance_uuid])
select_destinations.assert_called_once_with(None, fake_spec, select_destinations.assert_not_called()
[fake_spec.instance_uuid], None, None)
mock_get_ac.assert_called_once_with(mock_rfrs.return_value) mock_get_ac.assert_called_once_with(mock_rfrs.return_value)
@mock.patch('nova.scheduler.utils.resources_from_request_spec') def test_select_destination_old_placement(self):
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.' """Tests that we will raise NoValidhost when the scheduler
'get_allocation_candidates', return_value=None) report client's get_allocation_candidates() returns None, None as it
def test_select_destination_placement_connect_fails( would if placement service hasn't been upgraded before scheduler.
self, mock_get_ac, mock_rfrs): """
"""Tests that we will pass None for the provider_summaries parameter to place_res = (None, None)
the scheduler driver select_destinations() method when the scheduler self._test_select_destination(place_res)
def test_select_destination_placement_connect_fails(self):
"""Tests that we will raise NoValidHost when the scheduler
report client's get_allocation_candidates() returns None, which it report client's get_allocation_candidates() returns None, which it
would if the connection to Placement failed and the safe_connect would if the connection to Placement failed and the safe_connect
decorator returns None. decorator returns None.
""" """
fake_spec = objects.RequestSpec() place_res = None
fake_spec.instance_uuid = uuids.instance self._test_select_destination(place_res)
with mock.patch.object(self.manager.driver,
'select_destinations') as select_destinations:
self.manager.select_destinations(
self.context, spec_obj=fake_spec,
instance_uuids=[fake_spec.instance_uuid])
select_destinations.assert_called_once_with(
self.context, fake_spec, [fake_spec.instance_uuid], None, None)
mock_get_ac.assert_called_once_with(mock_rfrs.return_value)
@mock.patch('nova.scheduler.utils.resources_from_request_spec') def test_select_destination_no_candidates(self):
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.' """Tests that we will raise NoValidHost when the scheduler
'get_allocation_candidates')
def test_select_destination_no_candidates(self, mock_get_ac, mock_rfrs):
"""Tests that we will pass None for the provider_summaries parameter to
the scheduler driver select_destinations() method when the scheduler
report client's get_allocation_candidates() returns [], {} which it report client's get_allocation_candidates() returns [], {} which it
would if placement service hasn't yet had compute nodes populate would if placement service hasn't yet had compute nodes populate
inventory. inventory.
""" """
fake_spec = objects.RequestSpec()
fake_spec.instance_uuid = uuids.instance
place_res = ([], {}) place_res = ([], {})
mock_get_ac.return_value = place_res self._test_select_destination(place_res)
with mock.patch.object(self.manager.driver, 'select_destinations'
) as select_destinations:
self.manager.select_destinations(None, spec_obj=fake_spec,
instance_uuids=[fake_spec.instance_uuid])
select_destinations.assert_called_once_with(None, fake_spec,
[fake_spec.instance_uuid], None, None)
mock_get_ac.assert_called_once_with(mock_rfrs.return_value)
@mock.patch('nova.scheduler.utils.resources_from_request_spec') @mock.patch('nova.scheduler.utils.resources_from_request_spec')
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.' @mock.patch('nova.scheduler.client.report.SchedulerReportClient.'