diff --git a/nova/conductor/manager.py b/nova/conductor/manager.py index c75da0cd5a6d..a347ec67532b 100644 --- a/nova/conductor/manager.py +++ b/nova/conductor/manager.py @@ -1031,7 +1031,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 @@ -1067,6 +1068,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( @@ -1105,7 +1114,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 = {} @@ -1128,9 +1138,10 @@ class ComputeTaskManager(base.Base): LOG.error('No host-to-cell mapping found for selected ' 'host %(host)s. Setup is incomplete.', {'host': host.service_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 diff --git a/nova/tests/unit/conductor/test_conductor.py b/nova/tests/unit/conductor/test_conductor.py index 7d6cfd6fda3b..4bcaacba7305 100644 --- a/nova/tests/unit/conductor/test_conductor.py +++ b/nova/tests/unit/conductor/test_conductor.py @@ -1856,12 +1856,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 = [[fake_selection1]] @@ -2002,6 +2005,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