Handle HostMappingNotFound when deleting a compute service

If the compute service we're deleting has never been
discovered (mapped to a cell using discover_hosts) or the
host mapping was already deleted, we need to handle the
HostMappingNotFound error when deleting a compute service
so that we (1) don't 500 out of the API and (2) continue to
delete the compute service.

Change-Id: I0d7644db3537a67b94e75972b3c4fce25a623763
Closes-Bug: #1780727
(cherry picked from commit ee6e0c1e7e)
This commit is contained in:
Matt Riedemann 2018-07-13 15:42:03 -04:00
parent d7864fbb9c
commit 0be8cbc302
2 changed files with 41 additions and 2 deletions

View File

@ -240,8 +240,14 @@ class ServiceController(wsgi.Controller):
self.placementclient.delete_resource_provider(
context, service.compute_node, cascade=True)
# remove the host_mapping of this host.
hm = objects.HostMapping.get_by_host(context, service.host)
hm.destroy()
try:
hm = objects.HostMapping.get_by_host(context, service.host)
hm.destroy()
except exception.HostMappingNotFound:
# It's possible to startup a nova-compute service and then
# delete it (maybe it was accidental?) before mapping it to
# a cell using discover_hosts, so we just ignore this.
pass
self.host_api.service_delete(context, id)
except exception.ServiceNotFound:

View File

@ -704,6 +704,39 @@ class ServicesTestV21(test.TestCase):
self.controller.delete, self.req, 1234)
self.assertTrue(host_api.service_delete.called)
@mock.patch('nova.objects.InstanceList.get_uuids_by_host',
return_value=objects.InstanceList())
@mock.patch('nova.objects.HostMapping.get_by_host',
side_effect=exception.HostMappingNotFound(name='host1'))
def test_compute_service_delete_host_mapping_not_found(
self, get_instances, get_hm):
"""Tests that we are still able to successfully delete a nova-compute
service even if the HostMapping is not found.
"""
@mock.patch.object(self.controller.host_api, 'service_get_by_id',
return_value=objects.Service(
host='host1', binary='nova-compute',
compute_node=objects.ComputeNode()))
@mock.patch.object(self.controller.aggregate_api,
'get_aggregates_by_host',
return_value=objects.AggregateList())
@mock.patch.object(self.controller.placementclient,
'delete_resource_provider')
@mock.patch.object(self.controller.host_api, 'service_delete')
def _test(service_delete, delete_resource_provider,
get_aggregates_by_host, service_get_by_id):
self.controller.delete(self.req, 2)
ctxt = self.req.environ['nova.context']
service_get_by_id.assert_called_once_with(ctxt, 2)
get_instances.assert_called_once_with(ctxt, 'host1')
get_aggregates_by_host.assert_called_once_with(ctxt, 'host1')
delete_resource_provider.assert_called_once_with(
ctxt, service_get_by_id.return_value.compute_node,
cascade=True)
get_hm.assert_called_once_with(ctxt, 'host1')
service_delete.assert_called_once_with(ctxt, 2)
_test()
# This test is just to verify that the servicegroup API gets used when
# calling the API
@mock.patch.object(db_driver.DbDriver, 'is_up', side_effect=KeyError)