Merge "Remove cell api overrides for force-delete"

This commit is contained in:
Jenkins 2015-08-12 03:09:41 +00:00 committed by Gerrit Code Review
commit e9efd20e47
10 changed files with 70 additions and 40 deletions

View File

@ -76,7 +76,7 @@ class CellsManager(manager.Manager):
Scheduling requests get passed to the scheduler class.
"""
target = oslo_messaging.Target(version='1.35')
target = oslo_messaging.Target(version='1.36')
def __init__(self, *args, **kwargs):
LOG.warning(_LW('The cells feature of Nova is considered experimental '
@ -523,9 +523,12 @@ class CellsManager(manager.Manager):
"""Resume an instance in its cell."""
self.msg_runner.resume_instance(ctxt, instance)
def terminate_instance(self, ctxt, instance):
def terminate_instance(self, ctxt, instance, delete_type='delete'):
"""Delete an instance in its cell."""
self.msg_runner.terminate_instance(ctxt, instance)
# NOTE(rajesht): The `delete_type` parameter is passed so that it will
# be routed to destination cell, where instance deletion will happen.
self.msg_runner.terminate_instance(ctxt, instance,
delete_type=delete_type)
def soft_delete_instance(self, ctxt, instance):
"""Soft-delete an instance in its cell."""

View File

@ -832,7 +832,7 @@ class _TargetedMessageMethods(_BaseMessageMethods):
self.msg_runner.instance_destroy_at_top(ctxt,
instance)
except exception.InstanceInfoCacheNotFound:
if method != 'delete':
if method not in ('delete', 'force_delete'):
raise
fn = getattr(self.compute_api, method, None)
@ -865,8 +865,8 @@ class _TargetedMessageMethods(_BaseMessageMethods):
def get_host_uptime(self, message, host_name):
return self.host_api.get_host_uptime(message.ctxt, host_name)
def terminate_instance(self, message, instance):
self._call_compute_api_with_obj(message.ctxt, instance, 'delete')
def terminate_instance(self, message, instance, delete_type='delete'):
self._call_compute_api_with_obj(message.ctxt, instance, delete_type)
def soft_delete_instance(self, message, instance):
self._call_compute_api_with_obj(message.ctxt, instance, 'soft_delete')
@ -1711,8 +1711,10 @@ class MessageRunner(object):
"""Resume an instance in its cell."""
self._instance_action(ctxt, instance, 'resume_instance')
def terminate_instance(self, ctxt, instance):
self._instance_action(ctxt, instance, 'terminate_instance')
def terminate_instance(self, ctxt, instance, delete_type='delete'):
extra_kwargs = dict(delete_type=delete_type)
self._instance_action(ctxt, instance, 'terminate_instance',
extra_kwargs=extra_kwargs)
def soft_delete_instance(self, ctxt, instance):
self._instance_action(ctxt, instance, 'soft_delete_instance')

View File

@ -116,6 +116,7 @@ class CellsAPI(object):
* 1.35 - Make instance_update_at_top, instance_destroy_at_top
and instance_info_cache_update_at_top use instance objects
* 1.36 - Added 'delete_type' parameter to terminate_instance()
'''
VERSION_ALIASES = {
@ -564,15 +565,22 @@ class CellsAPI(object):
cctxt = self.client.prepare(version='1.15')
cctxt.cast(ctxt, 'resume_instance', instance=instance)
def terminate_instance(self, ctxt, instance, bdms, reservations=None):
def terminate_instance(self, ctxt, instance, bdms, reservations=None,
delete_type='delete'):
"""Delete an instance in its cell.
This method takes a new-world instance object.
"""
if not CONF.cells.enable:
return
cctxt = self.client.prepare(version='1.18')
cctxt.cast(ctxt, 'terminate_instance', instance=instance)
msg_kwargs = {'instance': instance}
if self.client.can_send_version('1.36'):
version = '1.36'
msg_kwargs['delete_type'] = delete_type
else:
version = '1.18'
cctxt = self.client.prepare(version=version)
cctxt.cast(ctxt, 'terminate_instance', **msg_kwargs)
def soft_delete_instance(self, ctxt, instance, reservations=None):
"""Soft-delete an instance in its cell.

View File

@ -1805,7 +1805,20 @@ class API(base.Base):
instance.save()
else:
self.compute_rpcapi.terminate_instance(context, instance, bdms,
reservations=reservations)
reservations=reservations,
delete_type='delete')
def _do_force_delete(self, context, instance, bdms, reservations=None,
local=False):
if local:
instance.vm_state = vm_states.DELETED
instance.task_state = None
instance.terminated_at = timeutils.utcnow()
instance.save()
else:
self.compute_rpcapi.terminate_instance(context, instance, bdms,
reservations=reservations,
delete_type='force_delete')
def _do_soft_delete(self, context, instance, bdms, reservations=None,
local=False):
@ -1881,7 +1894,7 @@ class API(base.Base):
@check_instance_state(must_have_launched=False)
def force_delete(self, context, instance):
"""Force delete an instance in any vm_state/task_state."""
self._delete(context, instance, 'force_delete', self._do_delete,
self._delete(context, instance, 'force_delete', self._do_force_delete,
task_state=task_states.DELETING)
def force_stop(self, context, instance, do_cast=True, clean_shutdown=True):

View File

@ -206,6 +206,9 @@ class ComputeCellsAPI(compute_api.API):
"""
pass
def force_delete(self, context, instance):
self._handle_cell_delete(context, instance, 'force_delete')
def soft_delete(self, context, instance):
self._handle_cell_delete(context, instance, 'soft_delete')
@ -259,12 +262,6 @@ class ComputeCellsAPI(compute_api.API):
super(ComputeCellsAPI, self).restore(context, instance)
self._cast_to_cells(context, instance, 'restore')
@check_instance_cell
def force_delete(self, context, instance):
"""Force delete a previously deleted (but not reclaimed) instance."""
super(ComputeCellsAPI, self).force_delete(context, instance)
self._cast_to_cells(context, instance, 'force_delete')
@check_instance_cell
def evacuate(self, context, instance, *args, **kwargs):
"""Evacuate the given instance with the provided attributes."""

View File

@ -796,7 +796,11 @@ class ComputeAPI(object):
version=version)
cctxt.cast(ctxt, 'suspend_instance', instance=instance)
def terminate_instance(self, ctxt, instance, bdms, reservations=None):
def terminate_instance(self, ctxt, instance, bdms, reservations=None,
delete_type=None):
# NOTE(rajesht): The `delete_type` parameter is passed because
# the method signature has to match with `terminate_instance()`
# method of cells rpcapi.
version = '4.0'
cctxt = self.client.prepare(server=_compute_host(None, instance),
version=version)

View File

@ -785,10 +785,12 @@ class CellsManagerClassTestCase(test.NoDBTestCase):
def test_terminate_instance(self):
self.mox.StubOutWithMock(self.msg_runner, 'terminate_instance')
self.msg_runner.terminate_instance(self.ctxt, 'fake-instance')
self.msg_runner.terminate_instance(self.ctxt, 'fake-instance',
delete_type='delete')
self.mox.ReplayAll()
self.cells_manager.terminate_instance(self.ctxt,
instance='fake-instance')
instance='fake-instance',
delete_type='delete')
def test_soft_delete_instance(self):
self.mox.StubOutWithMock(self.msg_runner, 'soft_delete_instance')

View File

@ -634,10 +634,12 @@ class CellsAPITestCase(test.NoDBTestCase):
call_info = self._stub_rpc_method('cast', None)
self.cells_rpcapi.terminate_instance(self.fake_context,
'fake-instance', [])
expected_args = {'instance': 'fake-instance'}
'fake-instance', [],
delete_type='delete')
expected_args = {'instance': 'fake-instance',
'delete_type': 'delete'}
self._check_result(call_info, 'terminate_instance',
expected_args, version='1.18')
expected_args, version='1.36')
def test_soft_delete_instance(self):
call_info = self._stub_rpc_method('cast', None)

View File

@ -874,7 +874,8 @@ class _ComputeAPIUnitTestMixIn(object):
reservations=cast_reservations)
elif delete_type in ['delete', 'force_delete']:
rpcapi.terminate_instance(self.context, inst, [],
reservations=cast_reservations)
reservations=cast_reservations,
delete_type=delete_type)
if commit_quotas:
# Local delete or when we're testing API cell.
@ -985,7 +986,7 @@ class _ComputeAPIUnitTestMixIn(object):
rpcapi.terminate_instance(
self.context, inst,
mox.IsA(objects.BlockDeviceMappingList),
reservations=None)
reservations=None, delete_type='delete')
else:
compute_utils.notify_about_instance_usage(
self.compute_api.notifier, self.context,

View File

@ -138,17 +138,18 @@ class CellsComputeAPITestCase(test_compute.ComputeAPITestCase):
def test_error_evacuate(self):
self.skipTest("Test is incompatible with cells.")
def test_delete_instance_no_cell(self):
def _test_delete_instance_no_cell(self, method_name):
cells_rpcapi = self.compute_api.cells_rpcapi
self.mox.StubOutWithMock(cells_rpcapi,
'instance_delete_everywhere')
inst = self._create_fake_instance_obj()
delete_type = method_name == 'soft_delete' and 'soft' or 'hard'
cells_rpcapi.instance_delete_everywhere(self.context,
inst, 'hard')
inst, delete_type)
self.mox.ReplayAll()
self.stubs.Set(self.compute_api.network_api, 'deallocate_for_instance',
lambda *a, **kw: None)
self.compute_api.delete(self.context, inst)
getattr(self.compute_api, method_name)(self.context, inst)
def test_delete_instance_no_cell_constraint_failure_does_not_loop(self):
with mock.patch.object(self.compute_api.cells_rpcapi,
@ -241,16 +242,13 @@ class CellsComputeAPITestCase(test_compute.ComputeAPITestCase):
_test()
def test_soft_delete_instance_no_cell(self):
cells_rpcapi = self.compute_api.cells_rpcapi
self.mox.StubOutWithMock(cells_rpcapi,
'instance_delete_everywhere')
inst = self._create_fake_instance_obj()
cells_rpcapi.instance_delete_everywhere(self.context,
inst, 'soft')
self.mox.ReplayAll()
self.stubs.Set(self.compute_api.network_api, 'deallocate_for_instance',
lambda *a, **kw: None)
self.compute_api.soft_delete(self.context, inst)
self._test_delete_instance_no_cell('soft_delete')
def test_delete_instance_no_cell(self):
self._test_delete_instance_no_cell('delete')
def test_force_delete_instance_no_cell(self):
self._test_delete_instance_no_cell('force_delete')
def test_get_migrations(self):
filters = {'cell_name': 'ChildCell', 'status': 'confirmed'}