Enforce case-sensitive hostnames in aggregate host add

If we are using a case-insensitive backend database like mysql, a
user can request an aggregate host add with a non-matching hostname
and we will not signal failure. We will create a mapping which will
not actually include that host in the aggregate, which will be
confusing later. This change makes us fail if the host name does not
match exactly, which is the same behavior as if we are using a
case-sensitive backend (like postgres).

Change-Id: I597dee74d33de337913eddda74ab056fbf81a23c
Closes-Bug: #1709260
(cherry picked from commit c8e2de6684)
This commit is contained in:
Dan Smith 2018-09-24 13:36:39 -07:00 committed by Matt Riedemann
parent c8ea8ed466
commit c72bb2c747
3 changed files with 43 additions and 5 deletions

View File

@ -5325,14 +5325,23 @@ class AggregateAPI(base.Base):
try:
mapping = objects.HostMapping.get_by_host(context, host_name)
nova_context.set_target_cell(context, mapping.cell_mapping)
objects.Service.get_by_compute_host(context, host_name)
service = objects.Service.get_by_compute_host(context, host_name)
except exception.HostMappingNotFound:
try:
# NOTE(danms): This targets our cell
_find_service_in_cell(context, service_host=host_name)
service = _find_service_in_cell(context,
service_host=host_name)
except exception.NotFound:
raise exception.ComputeHostNotFound(host=host_name)
if service.host != host_name:
# NOTE(danms): If we found a service but it is not an
# exact match, we may have a case-insensitive backend
# database (like mysql) which will end up with us
# adding the host-aggregate mapping with a
# non-matching hostname.
raise exception.ComputeHostNotFound(host=host_name)
aggregate = objects.Aggregate.get_by_id(context, aggregate_id)
compute_utils.notify_about_aggregate_action(

View File

@ -12086,6 +12086,29 @@ class ComputeAPIAggrTestCase(BaseTestCase):
'compute.fake-mini')
mock_add_host.assert_not_called()
@mock.patch('nova.objects.Service.get_by_compute_host')
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
'aggregate_add_host')
def test_add_host_to_aggregate_raise_not_found_case(self, mock_add_host,
mock_get_service):
# Ensure ComputeHostNotFound is raised when adding a host with a
# hostname that doesn't exactly map what we have stored.
def return_anyway(context, host_name):
return objects.Service(host=host_name.upper())
mock_get_service.side_effect = return_anyway
aggr = self.api.create_aggregate(self.context, 'fake_aggregate',
'fake_zone')
fake_notifier.NOTIFICATIONS = []
values = _create_service_entries(self.context)
fake_host = values[0][1][0]
self.assertRaises(exception.ComputeHostNotFound,
self.api.add_host_to_aggregate,
self.context, aggr.id, fake_host)
mock_add_host.assert_not_called()
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
'aggregate_add_host')
@mock.patch('nova.objects.HostMapping.get_by_host')
@ -12285,7 +12308,9 @@ class ComputeAPIAggrCallsSchedulerTestCase(test.NoDBTestCase):
agg = objects.Aggregate(name='fake', metadata={}, uuid=uuids.agg)
agg.add_host = mock.Mock()
with test.nested(
mock.patch.object(objects.Service, 'get_by_compute_host'),
mock.patch.object(objects.Service, 'get_by_compute_host',
return_value=objects.Service(
host='fakehost')),
mock.patch.object(objects.Aggregate, 'get_by_id',
return_value=agg)):
self.api.add_host_to_aggregate(self.context, 1, 'fakehost')

View File

@ -721,8 +721,12 @@ class ComputeAggregateAPITestCase(test.TestCase):
fixtures.MockPatch('nova.objects.HostMapping.get_by_host'))
self.useFixture(
fixtures.MockPatch('nova.context.set_target_cell'))
self.useFixture(
fixtures.MockPatch('nova.objects.Service.get_by_compute_host'))
mock_service_get_by_compute_host = (
self.useFixture(
fixtures.MockPatch(
'nova.objects.Service.get_by_compute_host')).mock)
mock_service_get_by_compute_host.return_value = (
objects.Service(host='fake-host'))
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
'aggregate_add_host')