Merge "Minimal construct plumbing for nova service-list when a cell is down"

This commit is contained in:
Zuul 2018-11-05 19:33:36 +00:00 committed by Gerrit Code Review
commit c64b03d218
5 changed files with 70 additions and 8 deletions

View File

@ -54,10 +54,10 @@ class ServiceController(wsgi.Controller):
context.can(services_policies.BASE_POLICY_NAME)
_services = [
s
for s in self.host_api.service_get_all(context, set_zones=True,
all_cells=True)
if s['binary'] not in api_services
s
for s in self.host_api.service_get_all(context, set_zones=True,
all_cells=True, cell_down_support=False)
if s['binary'] not in api_services
]
host = ''

View File

@ -5079,7 +5079,7 @@ class HostAPI(base.Base):
return result
def service_get_all(self, context, filters=None, set_zones=False,
all_cells=False):
all_cells=False, cell_down_support=False):
"""Returns a list of services, optionally filtering the results.
If specified, 'filters' should be a dictionary containing services
@ -5087,6 +5087,10 @@ class HostAPI(base.Base):
the 'compute' topic, use filters={'topic': 'compute'}.
If all_cells=True, then scan all cells and merge the results.
If cell_down_support=True then return minimal service records
for cells that do not respond based on what we have in the
host mappings. These will have only 'binary' and 'host' set.
"""
if filters is None:
filters = {}
@ -5101,9 +5105,27 @@ class HostAPI(base.Base):
services = []
service_dict = nova_context.scatter_gather_all_cells(context,
objects.ServiceList.get_all, disabled, set_zones=set_zones)
for service in service_dict.values():
for cell_uuid, service in service_dict.items():
if not nova_context.is_cell_failure_sentinel(service):
services.extend(service)
elif cell_down_support:
unavailable_services = objects.ServiceList()
cid = [cm.id for cm in nova_context.CELLS
if cm.uuid == cell_uuid]
# We know cid[0] is in the list because we are using the
# same list that scatter_gather_all_cells used
hms = objects.HostMappingList.get_by_cell_id(context,
cid[0])
for hm in hms:
unavailable_services.objects.append(objects.Service(
binary='nova-compute', host=hm.host))
LOG.warning("Cell %s is not responding and hence only "
"partial results are available from this "
"cell.", cell_uuid)
services.extend(unavailable_services)
else:
LOG.warning("Cell %s is not responding and hence skipped "
"from the results.", cell_uuid)
else:
services = objects.ServiceList.get_all(context, disabled,
set_zones=set_zones)

View File

@ -557,7 +557,7 @@ class HostAPI(compute_api.HostAPI):
return self.cells_rpcapi.get_host_uptime(context, host_name)
def service_get_all(self, context, filters=None, set_zones=False,
all_cells=False):
all_cells=False, cell_down_support=False):
"""Get all services.
Note that this is the cellsv1 variant, which means we ignore the

View File

@ -121,7 +121,7 @@ fake_services_list = [
def fake_service_get_all(services):
def service_get_all(context, filters=None, set_zones=False,
all_cells=False):
all_cells=False, cell_down_support=False):
if set_zones or 'availability_zone' in filters:
return availability_zones.set_availability_zones(context,
services)

View File

@ -199,6 +199,42 @@ class ComputeHostAPITestCase(test.TestCase):
self.assertEqual(['host-%s' % uuids.cell1],
[svc.host for svc in services])
@mock.patch('nova.objects.CellMappingList.get_all')
@mock.patch.object(objects.HostMappingList, 'get_by_cell_id')
@mock.patch('nova.context.scatter_gather_all_cells')
def test_service_get_all_cells_with_minimal_constructs(self, mock_sg,
mock_get_hm,
mock_cm_list):
service = objects.Service(binary='nova-compute',
host='host-%s' % uuids.cell0)
cells = [
objects.CellMapping(uuid=uuids.cell1, id=1),
objects.CellMapping(uuid=uuids.cell2, id=2),
]
mock_cm_list.return_value = cells
context.load_cells()
# create two hms in cell1, which is the down cell in this test.
hm1 = objects.HostMapping(self.ctxt, host='host1-unavailable',
cell_mapping=cells[0])
hm1.create()
hm2 = objects.HostMapping(self.ctxt, host='host2-unavailable',
cell_mapping=cells[0])
hm2.create()
mock_sg.return_value = {
cells[0].uuid: [service],
cells[1].uuid: context.did_not_respond_sentinel,
}
mock_get_hm.return_value = [hm1, hm2]
services = self.host_api.service_get_all(self.ctxt, all_cells=True,
cell_down_support=True)
# returns the results from cell0 and minimal construct from cell1.
self.assertEqual(sorted(['host-%s' % uuids.cell0, 'host1-unavailable',
'host2-unavailable']),
sorted([svc.host for svc in services]))
mock_sg.assert_called_once_with(self.ctxt, objects.ServiceList.get_all,
None, set_zones=False)
mock_get_hm.assert_called_once_with(self.ctxt, cells[1].id)
def test_service_get_all_no_zones(self):
services = [dict(test_service.fake_service,
id=1, topic='compute', host='host1'),
@ -541,6 +577,10 @@ class ComputeHostAPICellsTestCase(ComputeHostAPITestCase):
def test_service_get_all_cells_with_failures(self):
pass
@testtools.skip('cellsv1 does not use this')
def test_service_get_all_cells_with_minimal_constructs(self):
pass
@testtools.skip('cellsv1 does not use this')
def test_service_delete_ambiguous(self):
pass