Skip to content

Commit

Permalink
Add support for clean_shutdown to resize in compute api layer
Browse files Browse the repository at this point in the history
Change Iec3dfd17725440958aac395ebc471e51afd6522e added
clean_shutdown support to the compute manager in Juno.
This change is part of a set to extend that to the compute
API layer, which will in turn allow us to extend the REST API
to provide a forced-shutdown option to those operations.

Change-Id: Ie93c3c4aa30b16e277628e1a741e46a37b794a75
Partially-Implements: blueprint user-defined-shutdown
  • Loading branch information
Phil Day committed Dec 19, 2014
1 parent 410038a commit a888996
Show file tree
Hide file tree
Showing 15 changed files with 156 additions and 71 deletions.
8 changes: 5 additions & 3 deletions nova/cells/manager.py
Expand Up @@ -74,7 +74,7 @@ class CellsManager(manager.Manager):
Scheduling requests get passed to the scheduler class.
"""

target = oslo_messaging.Target(version='1.32')
target = oslo_messaging.Target(version='1.33')

def __init__(self, *args, **kwargs):
LOG.warning(_LW('The cells feature of Nova is considered experimental '
Expand Down Expand Up @@ -523,10 +523,12 @@ def soft_delete_instance(self, ctxt, instance):
self.msg_runner.soft_delete_instance(ctxt, instance)

def resize_instance(self, ctxt, instance, flavor,
extra_instance_updates):
extra_instance_updates,
clean_shutdown=True):
"""Resize an instance in its cell."""
self.msg_runner.resize_instance(ctxt, instance,
flavor, extra_instance_updates)
flavor, extra_instance_updates,
clean_shutdown=clean_shutdown)

def live_migrate_instance(self, ctxt, instance, block_migration,
disk_over_commit, host_name):
Expand Down
9 changes: 6 additions & 3 deletions nova/cells/messaging.py
Expand Up @@ -894,10 +894,11 @@ def unpause_instance(self, message, instance):
self._call_compute_api_with_obj(message.ctxt, instance, 'unpause')

def resize_instance(self, message, instance, flavor,
extra_instance_updates):
extra_instance_updates, clean_shutdown=True):
"""Resize an instance via compute_api.resize()."""
self._call_compute_api_with_obj(message.ctxt, instance, 'resize',
flavor_id=flavor['flavorid'],
clean_shutdown=clean_shutdown,
**extra_instance_updates)

def live_migrate_instance(self, message, instance, block_migration,
Expand Down Expand Up @@ -1765,12 +1766,14 @@ def unpause_instance(self, ctxt, instance):
self._instance_action(ctxt, instance, 'unpause_instance')

def resize_instance(self, ctxt, instance, flavor,
extra_instance_updates):
extra_instance_updates,
clean_shutdown=True):
"""Resize an instance in its cell."""
extra_kwargs = dict(flavor=flavor,
extra_instance_updates=extra_instance_updates)
self._instance_action(ctxt, instance, 'resize_instance',
extra_kwargs=extra_kwargs)
extra_kwargs=extra_kwargs,
clean_shutdown=clean_shutdown)

def live_migrate_instance(self, ctxt, instance, block_migration,
disk_over_commit, host_name):
Expand Down
19 changes: 14 additions & 5 deletions nova/cells/rpcapi.py
Expand Up @@ -105,6 +105,7 @@ class CellsAPI(object):
* 1.30 - Make build_instances() use flavor object
* 1.31 - Add clean_shutdown to stop, resize, rescue, and shelve
* 1.32 - Send objects for instances in build_instances()
* 1.33 - Add clean_shutdown to resize_instance()
'''

VERSION_ALIASES = {
Expand Down Expand Up @@ -551,14 +552,22 @@ def soft_delete_instance(self, ctxt, instance, reservations=None):
cctxt.cast(ctxt, 'soft_delete_instance', instance=instance)

def resize_instance(self, ctxt, instance, extra_instance_updates,
scheduler_hint, flavor, reservations):
scheduler_hint, flavor, reservations,
clean_shutdown=True):
if not CONF.cells.enable:
return
flavor_p = jsonutils.to_primitive(flavor)
cctxt = self.client.prepare(version='1.20')
cctxt.cast(ctxt, 'resize_instance',
instance=instance, flavor=flavor_p,
extra_instance_updates=extra_instance_updates)
version = '1.33'
msg_args = {'instance': instance,
'flavor': flavor_p,
'extra_instance_updates': extra_instance_updates,
'clean_shutdown': clean_shutdown}
if not self.client.can_send_version(version):
del msg_args['clean_shutdown']
version = '1.20'

cctxt = self.client.prepare(version=version)
cctxt.cast(ctxt, 'resize_instance', **msg_args)

def live_migrate_instance(self, ctxt, instance, host_name,
block_migration, disk_over_commit):
Expand Down
5 changes: 3 additions & 2 deletions nova/compute/api.py
Expand Up @@ -2537,7 +2537,7 @@ def _resize_cells_support(context, quotas, instance,
@check_instance_lock
@check_instance_cell
@check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.STOPPED])
def resize(self, context, instance, flavor_id=None,
def resize(self, context, instance, flavor_id=None, clean_shutdown=True,
**extra_instance_updates):
"""Resize (ie, migrate) a running instance.
Expand Down Expand Up @@ -2638,7 +2638,8 @@ def resize(self, context, instance, flavor_id=None,
self.compute_task_api.resize_instance(context, instance,
extra_instance_updates, scheduler_hint=scheduler_hint,
flavor=new_instance_type,
reservations=quotas.reservations or [])
reservations=quotas.reservations or [],
clean_shutdown=clean_shutdown)

@wrap_check_policy
@check_instance_lock
Expand Down
13 changes: 8 additions & 5 deletions nova/compute/manager.py
Expand Up @@ -588,7 +588,7 @@ def wait_for_instance_event(self, instance, event_names, deadline=300,
class ComputeManager(manager.Manager):
"""Manages the running instances from creation to destruction."""

target = messaging.Target(version='3.37')
target = messaging.Target(version='3.38')

# How long to wait in seconds before re-issuing a shutdown
# signal to a instance during power off. The overall
Expand Down Expand Up @@ -3642,7 +3642,8 @@ def finish_revert_resize(self, context, instance, reservations, migration):
quotas.commit()

def _prep_resize(self, context, image, instance, instance_type,
quotas, request_spec, filter_properties, node):
quotas, request_spec, filter_properties, node,
clean_shutdown=True):

if not filter_properties:
filter_properties = {}
Expand Down Expand Up @@ -3675,14 +3676,16 @@ def _prep_resize(self, context, image, instance, instance_type,
LOG.audit(_('Migrating'), context=context, instance=instance)
self.compute_rpcapi.resize_instance(
context, instance, claim.migration, image,
instance_type, quotas.reservations)
instance_type, quotas.reservations,
clean_shutdown)

@wrap_exception()
@reverts_task_state
@wrap_instance_event
@wrap_instance_fault
def prep_resize(self, context, image, instance, instance_type,
reservations, request_spec, filter_properties, node):
reservations, request_spec, filter_properties, node,
clean_shutdown=True):
"""Initiates the process of moving a running instance to another host.
Possibly changes the RAM and disk size in the process.
Expand All @@ -3706,7 +3709,7 @@ def prep_resize(self, context, image, instance, instance_type,
self._prep_resize(context, image, instance,
instance_type, quotas,
request_spec, filter_properties,
node)
node, clean_shutdown)
# NOTE(dgenin): This is thrown in LibvirtDriver when the
# instance to be migrated is backed by LVM.
# Remove when LVM migration is implemented.
Expand Down
25 changes: 16 additions & 9 deletions nova/compute/rpcapi.py
Expand Up @@ -278,6 +278,7 @@ class ComputeAPI(object):
* 3.36 - Make build_and_run_instance() send a Flavor object
* 3.37 - Add clean_shutdown to stop, resize, rescue, shelve, and
shelve_offload
* 3.38 - Add clean_shutdown to prep_resize
'''

VERSION_ALIASES = {
Expand Down Expand Up @@ -561,18 +562,24 @@ def pre_live_migration(self, ctxt, instance, block_migration, disk,

def prep_resize(self, ctxt, image, instance, instance_type, host,
reservations=None, request_spec=None,
filter_properties=None, node=None):
version = '3.0'
filter_properties=None, node=None,
clean_shutdown=True):
instance_type_p = jsonutils.to_primitive(instance_type)
image_p = jsonutils.to_primitive(image)
msg_args = {'instance': instance,
'instance_type': instance_type_p,
'image': image_p,
'reservations': reservations,
'request_spec': request_spec,
'filter_properties': filter_properties,
'node': node,
'clean_shutdown': clean_shutdown}
version = '3.38'
if not self.client.can_send_version(version):
del msg_args['clean_shutdown']
version = '3.0'
cctxt = self.client.prepare(server=host, version=version)
cctxt.cast(ctxt, 'prep_resize',
instance=instance,
instance_type=instance_type_p,
image=image_p, reservations=reservations,
request_spec=request_spec,
filter_properties=filter_properties,
node=node)
cctxt.cast(ctxt, 'prep_resize', **msg_args)

def reboot_instance(self, ctxt, instance, block_device_info,
reboot_type):
Expand Down
16 changes: 10 additions & 6 deletions nova/conductor/api.py
Expand Up @@ -225,13 +225,15 @@ def __init__(self):
manager.ComputeTaskManager())

def resize_instance(self, context, instance, extra_instance_updates,
scheduler_hint, flavor, reservations):
scheduler_hint, flavor, reservations,
clean_shutdown=True):
# NOTE(comstud): 'extra_instance_updates' is not used here but is
# needed for compatibility with the cells_rpcapi version of this
# method.
self._manager.migrate_server(
context, instance, scheduler_hint, False, False, flavor,
None, None, reservations)
context, instance, scheduler_hint, live=False, rebuild=False,
flavor=flavor, block_migration=None, disk_over_commit=None,
reservations=reservations, clean_shutdown=clean_shutdown)

def live_migrate_instance(self, context, instance, host_name,
block_migration, disk_over_commit):
Expand Down Expand Up @@ -336,13 +338,15 @@ def __init__(self):
self.conductor_compute_rpcapi = rpcapi.ComputeTaskAPI()

def resize_instance(self, context, instance, extra_instance_updates,
scheduler_hint, flavor, reservations):
scheduler_hint, flavor, reservations,
clean_shutdown=True):
# NOTE(comstud): 'extra_instance_updates' is not used here but is
# needed for compatibility with the cells_rpcapi version of this
# method.
self.conductor_compute_rpcapi.migrate_server(
context, instance, scheduler_hint, False, False, flavor,
None, None, reservations)
context, instance, scheduler_hint, live=False, rebuild=False,
flavor=flavor, block_migration=None, disk_over_commit=None,
reservations=reservations, clean_shutdown=clean_shutdown)

def live_migrate_instance(self, context, instance, host_name,
block_migration, disk_over_commit):
Expand Down
12 changes: 7 additions & 5 deletions nova/conductor/manager.py
Expand Up @@ -461,7 +461,7 @@ class ComputeTaskManager(base.Base):
may involve coordinating activities on multiple compute nodes.
"""

target = messaging.Target(namespace='compute_task', version='1.10')
target = messaging.Target(namespace='compute_task', version='1.11')

def __init__(self):
super(ComputeTaskManager, self).__init__()
Expand All @@ -482,7 +482,8 @@ def __init__(self):
exception.MigrationPreCheckError,
exception.LiveMigrationWithOldNovaNotSafe)
def migrate_server(self, context, instance, scheduler_hint, live, rebuild,
flavor, block_migration, disk_over_commit, reservations=None):
flavor, block_migration, disk_over_commit, reservations=None,
clean_shutdown=True):
if instance and not isinstance(instance, nova_object.NovaObject):
# NOTE(danms): Until v2 of the RPC API, we need to tolerate
# old-world instance objects here
Expand All @@ -505,12 +506,12 @@ def migrate_server(self, context, instance, scheduler_hint, live, rebuild,
instance_uuid):
self._cold_migrate(context, instance, flavor,
scheduler_hint['filter_properties'],
reservations)
reservations, clean_shutdown)
else:
raise NotImplementedError()

def _cold_migrate(self, context, instance, flavor, filter_properties,
reservations):
reservations, clean_shutdown):
image_ref = instance.image_ref
image = compute_utils.get_image_metadata(
context, self.image_api, image_ref, instance)
Expand Down Expand Up @@ -555,7 +556,8 @@ def _cold_migrate(self, context, instance, flavor, filter_properties,
context, image, instance,
flavor, host,
reservations, request_spec=request_spec,
filter_properties=filter_properties, node=node)
filter_properties=filter_properties, node=node,
clean_shutdown=clean_shutdown)
except Exception as ex:
with excutils.save_and_reraise_exception():
updates = {'vm_state': instance['vm_state'],
Expand Down
25 changes: 15 additions & 10 deletions nova/conductor/rpcapi.py
Expand Up @@ -391,6 +391,7 @@ class ComputeTaskAPI(object):
1.8 - Add rebuild_instance
1.9 - Converted requested_networks to NetworkRequestList object
1.10 - Made migrate_server() and build_instances() send flavor objects
1.11 - Added clean_shutdown to migrate_server()
"""

Expand All @@ -404,22 +405,26 @@ def __init__(self):

def migrate_server(self, context, instance, scheduler_hint, live, rebuild,
flavor, block_migration, disk_over_commit,
reservations=None):
version = '1.10'
reservations=None, clean_shutdown=True):
kw = {'instance': instance, 'scheduler_hint': scheduler_hint,
'live': live, 'rebuild': rebuild, 'flavor': flavor,
'block_migration': block_migration,
'disk_over_commit': disk_over_commit,
'reservations': reservations,
'clean_shutdown': clean_shutdown}
version = '1.11'
if not self.client.can_send_version(version):
del kw['clean_shutdown']
version = '1.10'
if not self.client.can_send_version(version):
flavor = objects_base.obj_to_primitive(flavor)
kw['flavor'] = objects_base.obj_to_primitive(flavor)
version = '1.6'
if not self.client.can_send_version(version):
instance = jsonutils.to_primitive(
kw['instance'] = jsonutils.to_primitive(
objects_base.obj_to_primitive(instance))
version = '1.4'
cctxt = self.client.prepare(version=version)
return cctxt.call(context, 'migrate_server',
instance=instance, scheduler_hint=scheduler_hint,
live=live, rebuild=rebuild, flavor=flavor,
block_migration=block_migration,
disk_over_commit=disk_over_commit,
reservations=reservations)
return cctxt.call(context, 'migrate_server', **kw)

def build_instances(self, context, instances, image, filter_properties,
admin_password, injected_files, requested_networks,
Expand Down
14 changes: 11 additions & 3 deletions nova/tests/unit/cells/test_cells_manager.py
Expand Up @@ -758,14 +758,22 @@ def test_soft_delete_instance(self):
self.cells_manager.soft_delete_instance(self.ctxt,
instance='fake-instance')

def test_resize_instance(self):
def _test_resize_instance(self, clean_shutdown=True):
self.mox.StubOutWithMock(self.msg_runner, 'resize_instance')
self.msg_runner.resize_instance(self.ctxt, 'fake-instance',
'fake-flavor', 'fake-updates')
'fake-flavor', 'fake-updates',
clean_shutdown=clean_shutdown)
self.mox.ReplayAll()
self.cells_manager.resize_instance(
self.ctxt, instance='fake-instance', flavor='fake-flavor',
extra_instance_updates='fake-updates')
extra_instance_updates='fake-updates',
clean_shutdown=clean_shutdown)

def test_resize_instance(self):
self._test_resize_instance()

def test_resize_instance_forced_shutdown(self):
self._test_resize_instance(clean_shutdown=False)

def test_live_migrate_instance(self):
self.mox.StubOutWithMock(self.msg_runner, 'live_migrate_instance')
Expand Down
14 changes: 11 additions & 3 deletions nova/tests/unit/cells/test_cells_messaging.py
Expand Up @@ -1309,14 +1309,22 @@ def test_pause_instance(self):
def test_unpause_instance(self):
self._test_instance_action_method('unpause', (), {}, (), {}, False)

def test_resize_instance(self):
def _test_resize_instance(self, clean_shutdown=True):
kwargs = dict(flavor=dict(id=42, flavorid='orangemocchafrappuccino'),
extra_instance_updates=dict(cow='moo'))
expected_kwargs = dict(flavor_id='orangemocchafrappuccino', cow='moo')
extra_instance_updates=dict(cow='moo'),
clean_shutdown=clean_shutdown)
expected_kwargs = dict(flavor_id='orangemocchafrappuccino', cow='moo',
clean_shutdown=clean_shutdown)
self._test_instance_action_method('resize', (), kwargs,
(), expected_kwargs,
False)

def test_resize_instance(self):
self._test_resize_instance()

def test_resize_instance_forced_shutdown(self):
self._test_resize_instance(clean_shutdown=False)

def test_live_migrate_instance(self):
kwargs = dict(block_migration='fake-block-mig',
disk_over_commit='fake-commit',
Expand Down
8 changes: 5 additions & 3 deletions nova/tests/unit/cells/test_cells_rpcapi.py
Expand Up @@ -666,12 +666,14 @@ def test_resize_instance(self):
dict(cow='moo'),
'fake-hint',
'fake-flavor',
'fake-reservations')
'fake-reservations',
clean_shutdown=True)
expected_args = {'instance': 'fake-instance',
'flavor': 'fake-flavor',
'extra_instance_updates': dict(cow='moo')}
'extra_instance_updates': dict(cow='moo'),
'clean_shutdown': True}
self._check_result(call_info, 'resize_instance',
expected_args, version='1.20')
expected_args, version='1.33')

def test_live_migrate_instance(self):
call_info = self._stub_rpc_method('cast', None)
Expand Down

0 comments on commit a888996

Please sign in to comment.