Store block device mappings in cell0
If an instance fails to get scheduled, it gets buried in cell0 but
none of it's block device mappings are stored. At the API layer,
Nova reserves and creates attachments for new instances when
it gets a create request so these attachments are orphaned if the
block device mappings are not registered in the database somewhere.
This patch makes sure that if an instance is being buried in cell0,
all of it's block device mappings are recorded as well so they can
be later removed when the instance is deleted.
Conflicts:
nova/conductor/manager.py
Change-Id: I64074923fb741fbf5459f66b8ab1a23c16f3303f
Related-Bug: #1404867
(cherry picked from commit ad9e2a568f
)
This commit is contained in:
parent
372ecddc77
commit
51027abfd6
|
@ -985,7 +985,8 @@ class ComputeTaskManager(base.Base):
|
|||
return tags
|
||||
|
||||
def _bury_in_cell0(self, context, request_spec, exc,
|
||||
build_requests=None, instances=None):
|
||||
build_requests=None, instances=None,
|
||||
block_device_mapping=None):
|
||||
"""Ensure all provided build_requests and instances end up in cell0.
|
||||
|
||||
Cell0 is the fake cell we schedule dead instances to when we can't
|
||||
|
@ -1022,6 +1023,14 @@ class ComputeTaskManager(base.Base):
|
|||
for instance in instances_by_uuid.values():
|
||||
with obj_target_cell(instance, cell0) as cctxt:
|
||||
instance.create()
|
||||
|
||||
# NOTE(mnaser): In order to properly clean-up volumes after
|
||||
# being buried in cell0, we need to store BDMs.
|
||||
if block_device_mapping:
|
||||
self._create_block_device_mapping(
|
||||
cell0, instance.flavor, instance.uuid,
|
||||
block_device_mapping)
|
||||
|
||||
# Use the context targeted to cell0 here since the instance is
|
||||
# now in cell0.
|
||||
self._set_vm_state_and_notify(
|
||||
|
@ -1060,7 +1069,8 @@ class ComputeTaskManager(base.Base):
|
|||
except Exception as exc:
|
||||
LOG.exception('Failed to schedule instances')
|
||||
self._bury_in_cell0(context, request_specs[0], exc,
|
||||
build_requests=build_requests)
|
||||
build_requests=build_requests,
|
||||
block_device_mapping=block_device_mapping)
|
||||
return
|
||||
|
||||
host_mapping_cache = {}
|
||||
|
@ -1080,9 +1090,10 @@ class ComputeTaskManager(base.Base):
|
|||
LOG.error('No host-to-cell mapping found for selected '
|
||||
'host %(host)s. Setup is incomplete.',
|
||||
{'host': host['host']})
|
||||
self._bury_in_cell0(context, request_spec, exc,
|
||||
build_requests=[build_request],
|
||||
instances=[instance])
|
||||
self._bury_in_cell0(
|
||||
context, request_spec, exc,
|
||||
build_requests=[build_request], instances=[instance],
|
||||
block_device_mapping=block_device_mapping)
|
||||
# This is a placeholder in case the quota recheck fails.
|
||||
instances.append(None)
|
||||
continue
|
||||
|
|
|
@ -1802,12 +1802,15 @@ class ConductorTaskTestCase(_BaseTaskTestCase, test_compute.BaseTestCase):
|
|||
select_dest,
|
||||
build_and_run):
|
||||
def _fake_bury(ctxt, request_spec, exc,
|
||||
build_requests=None, instances=None):
|
||||
build_requests=None, instances=None,
|
||||
block_device_mapping=None):
|
||||
self.assertIn('not mapped to any cell', str(exc))
|
||||
self.assertEqual(1, len(build_requests))
|
||||
self.assertEqual(1, len(instances))
|
||||
self.assertEqual(build_requests[0].instance_uuid,
|
||||
instances[0].uuid)
|
||||
self.assertEqual(self.params['block_device_mapping'],
|
||||
block_device_mapping)
|
||||
|
||||
bury.side_effect = _fake_bury
|
||||
select_dest.return_value = [{'host': 'missing-host',
|
||||
|
@ -1954,6 +1957,27 @@ class ConductorTaskTestCase(_BaseTaskTestCase, test_compute.BaseTestCase):
|
|||
|
||||
self.assertEqual(expected, inst_states)
|
||||
|
||||
@mock.patch.object(objects.CellMapping, 'get_by_uuid')
|
||||
@mock.patch.object(conductor_manager.ComputeTaskManager,
|
||||
'_create_block_device_mapping')
|
||||
def test_bury_in_cell0_with_block_device_mapping(self, mock_create_bdm,
|
||||
mock_get_cell):
|
||||
mock_get_cell.return_value = self.cell_mappings['cell0']
|
||||
|
||||
inst_br = fake_build_request.fake_req_obj(self.ctxt)
|
||||
del inst_br.instance.id
|
||||
inst_br.create()
|
||||
inst = inst_br.get_new_instance(self.ctxt)
|
||||
|
||||
self.conductor._bury_in_cell0(
|
||||
self.ctxt, self.params['request_specs'][0], Exception('Foo'),
|
||||
build_requests=[inst_br], instances=[inst],
|
||||
block_device_mapping=self.params['block_device_mapping'])
|
||||
|
||||
mock_create_bdm.assert_called_once_with(
|
||||
self.cell_mappings['cell0'], inst.flavor, inst.uuid,
|
||||
self.params['block_device_mapping'])
|
||||
|
||||
def test_reset(self):
|
||||
with mock.patch('nova.compute.rpcapi.ComputeAPI') as mock_rpc:
|
||||
old_rpcapi = self.conductor_manager.compute_rpcapi
|
||||
|
|
Loading…
Reference in New Issue