Minimal construct plumbing for nova service-list when a cell is down
This patch modifies the existing behavior of nova service-list which ignores a down cell to returning a partial construct consisting of the binary and host info obtained from the API host_mappings table for the compute services in the down cells. This is enabled by passing a new enough microversion, which is added in a later patch in this series. Related to blueprint handling-down-cell Change-Id: I9cf5e4eb7f70c495001fd064c060d7d5b3dd5bff
This commit is contained in:
parent
ef5aa8a818
commit
870d718c17
|
@ -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 = ''
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue