Browse Source

Merge "Bump the Compute RPC API to version 6.0"

changes/79/781079/2
Zuul 4 months ago
committed by Gerrit Code Review
parent
commit
572ae578bb
  1. 265
      nova/compute/manager.py
  2. 317
      nova/compute/rpcapi.py
  3. 4
      nova/objects/service.py
  4. 2
      nova/tests/functional/integrated_helpers.py
  5. 12
      nova/tests/functional/libvirt/test_numa_live_migration.py
  6. 2
      nova/tests/functional/test_compute_mgr.py
  7. 259
      nova/tests/unit/compute/test_compute.py
  8. 62
      nova/tests/unit/compute/test_compute_mgr.py
  9. 340
      nova/tests/unit/compute/test_rpcapi.py
  10. 18
      nova/tests/unit/compute/test_shelve.py

265
nova/compute/manager.py

@ -525,7 +525,7 @@ class ComputeVirtAPI(virtapi.VirtAPI):
class ComputeManager(manager.Manager):
"""Manages the running instances from creation to destruction."""
target = messaging.Target(version='5.13')
target = messaging.Target(version='6.0')
def __init__(self, compute_driver=None, *args, **kwargs):
"""Load configuration options and connect to the hypervisor."""
@ -571,6 +571,9 @@ class ComputeManager(manager.Manager):
super(ComputeManager, self).__init__(service_name="compute",
*args, **kwargs)
# TODO(sbauza): Remove this call once we delete the V5Proxy class
self.additional_endpoints.append(_ComputeV5Proxy(self))
# NOTE(russellb) Load the driver last. It may call back into the
# compute manager via the virtapi, so we want it to be fully
# initialized before that happens.
@ -1561,34 +1564,6 @@ class ComputeManager(manager.Manager):
except exception.InstanceNotFound:
return power_state.NOSTATE
# TODO(stephenfin): Remove this once we bump the compute API to v6.0
def get_console_topic(self, context):
"""Retrieves the console host for a project on this host.
Currently this is just set in the flags for each compute host.
"""
# TODO(mdragon): perhaps make this variable by console_type?
return 'console.%s' % CONF.console_host
# TODO(stephenfin): Remove this once we bump the compute API to v6.0
@wrap_exception()
def get_console_pool_info(self, context, console_type):
raise NotImplementedError()
# TODO(stephenfin): Remove this as it's nova-network only
@wrap_exception()
def refresh_instance_security_rules(self, context, instance):
"""Tell the virtualization driver to refresh security rules for
an instance.
Passes straight through to the virtualization driver.
Synchronize the call because we may still be in the middle of
creating the instance.
"""
pass
def _await_block_device_map_created(self, context, vol_id):
# TODO(yamahata): creating volume simultaneously
# reduces creation time?
@ -2092,10 +2067,10 @@ class ComputeManager(manager.Manager):
@reverts_task_state
@wrap_instance_fault
def build_and_run_instance(self, context, instance, image, request_spec,
filter_properties, admin_password=None,
filter_properties, accel_uuids, admin_password=None,
injected_files=None, requested_networks=None,
security_groups=None, block_device_mapping=None,
node=None, limits=None, host_list=None, accel_uuids=None):
node=None, limits=None, host_list=None):
@utils.synchronized(instance.uuid)
def _locked_do_build_and_run_instance(*args, **kwargs):
@ -2313,6 +2288,8 @@ class ComputeManager(manager.Manager):
port_id, to resource provider UUID that provides resource for that
RequestGroup. Or None if the request_spec was None.
"""
# TODO(sbauza): Remove this conditional once we only support
# RPC API 6.0
if request_spec:
return request_spec.get_request_group_mapping()
else:
@ -3320,8 +3297,7 @@ class ComputeManager(manager.Manager):
injected_files, new_pass, orig_sys_metadata,
bdms, recreate, on_shared_storage,
preserve_ephemeral, migration,
scheduled_node, limits, request_spec,
accel_uuids=None):
scheduled_node, limits, request_spec, accel_uuids):
"""Destroy and re-make this instance.
A 'rebuild' effectively purges all existing data from the system and
@ -3352,8 +3328,7 @@ class ComputeManager(manager.Manager):
:param limits: Overcommit limits set by the scheduler. If a host was
specified by the user, this will be None
:param request_spec: a RequestSpec object used to schedule the instance
:param accel_uuids: a list of cyborg ARQ uuids or None if the RPC API
is <=5.11
:param accel_uuids: a list of cyborg ARQ uuids
"""
# recreate=True means the instance is being evacuated from a failed
@ -4222,12 +4197,6 @@ class ComputeManager(manager.Manager):
self.host, action=fields.NotificationAction.UNRESCUE,
phase=fields.NotificationPhase.END)
# TODO(stephenfin): Remove this once we bump the compute API to v6.0
@wrap_exception()
@wrap_instance_fault
def change_instance_metadata(self, context, diff, instance):
raise NotImplementedError()
@wrap_exception()
@wrap_instance_event(prefix='compute')
@errors_out_migration
@ -4817,7 +4786,7 @@ class ComputeManager(manager.Manager):
@wrap_instance_event(prefix='compute')
@errors_out_migration
@wrap_instance_fault
def revert_resize(self, context, instance, migration, request_spec=None):
def revert_resize(self, context, instance, migration, request_spec):
"""Destroys the new instance on the destination machine.
Reverts the model changes, and powers on the old instance on the
@ -4909,8 +4878,7 @@ class ComputeManager(manager.Manager):
@wrap_instance_event(prefix='compute')
@errors_out_migration
@wrap_instance_fault
def finish_revert_resize(
self, context, instance, migration, request_spec=None):
def finish_revert_resize(self, context, instance, migration, request_spec):
"""Finishes the second half of reverting a resize on the source host.
Bring the original source instance state back (active/shutoff) and
@ -5033,6 +5001,8 @@ class ComputeManager(manager.Manager):
provider_mappings = self._get_request_group_mapping(
request_spec)
else:
# TODO(sbauza): Remove this conditional once we only support RPC
# API 6.0
# NOTE(gibi): The compute RPC is pinned to be older than 5.2
# and therefore request_spec is not sent. We cannot calculate
# the provider mappings. If the instance has ports with
@ -5180,7 +5150,7 @@ class ComputeManager(manager.Manager):
@reverts_task_state
@wrap_instance_event(prefix='compute')
@wrap_instance_fault
def prep_resize(self, context, image, instance, instance_type,
def prep_resize(self, context, image, instance, flavor,
request_spec, filter_properties, node,
clean_shutdown, migration, host_list):
"""Initiates the process of moving a running instance to another host.
@ -5206,10 +5176,10 @@ class ComputeManager(manager.Manager):
errors_out_migration_ctxt(migration):
self._send_prep_resize_notifications(
context, instance, fields.NotificationPhase.START,
instance_type)
flavor)
try:
self._prep_resize(context, image, instance,
instance_type, filter_properties,
flavor, filter_properties,
node, migration, request_spec,
clean_shutdown)
except exception.BuildAbortException:
@ -5227,12 +5197,12 @@ class ComputeManager(manager.Manager):
# try to re-schedule the resize elsewhere:
exc_info = sys.exc_info()
self._reschedule_resize_or_reraise(context, instance,
exc_info, instance_type, request_spec,
exc_info, flavor, request_spec,
filter_properties, host_list)
finally:
self._send_prep_resize_notifications(
context, instance, fields.NotificationPhase.END,
instance_type)
flavor)
def _reschedule_resize_or_reraise(self, context, instance, exc_info,
instance_type, request_spec, filter_properties, host_list):
@ -5308,14 +5278,12 @@ class ComputeManager(manager.Manager):
raise exc.with_traceback(exc_info[2])
raise exc
# TODO(stephenfin): Remove unused request_spec parameter in API v6.0
@messaging.expected_exceptions(exception.MigrationPreCheckError)
@wrap_exception()
@wrap_instance_event(prefix='compute')
@wrap_instance_fault
def prep_snapshot_based_resize_at_dest(
self, ctxt, instance, flavor, nodename, migration, limits,
request_spec):
self, ctxt, instance, flavor, nodename, migration, limits):
"""Performs pre-cross-cell resize resource claim on the dest host.
This runs on the destination host in a cross-cell resize operation
@ -5338,7 +5306,6 @@ class ComputeManager(manager.Manager):
:param nodename: Name of the target compute node
:param migration: nova.objects.Migration object for the operation
:param limits: nova.objects.SchedulerLimits object of resource limits
:param request_spec: nova.objects.RequestSpec object for the operation
:returns: nova.objects.MigrationContext; the migration context created
on the destination host during the resize_claim.
:raises: nova.exception.MigrationPreCheckError if the pre-check
@ -5523,8 +5490,8 @@ class ComputeManager(manager.Manager):
@wrap_instance_event(prefix='compute')
@wrap_instance_fault
def resize_instance(self, context, instance, image,
migration, instance_type, clean_shutdown,
request_spec=None):
migration, flavor, clean_shutdown,
request_spec):
"""Starts the migration of a running instance to another host.
This is initiated from the destination host's ``prep_resize`` routine
@ -5532,7 +5499,7 @@ class ComputeManager(manager.Manager):
"""
try:
self._resize_instance(context, instance, image, migration,
instance_type, clean_shutdown, request_spec)
flavor, clean_shutdown, request_spec)
except Exception:
with excutils.save_and_reraise_exception():
self._revert_allocation(context, instance, migration)
@ -5791,7 +5758,7 @@ class ComputeManager(manager.Manager):
@errors_out_migration
@wrap_instance_fault
def finish_resize(self, context, disk_info, image, instance,
migration, request_spec=None):
migration, request_spec):
"""Completes the migration process.
Sets up the newly transferred disk and turns on the instance at its
@ -5866,14 +5833,13 @@ class ComputeManager(manager.Manager):
action=fields.NotificationAction.RESIZE_FINISH, phase=phase,
bdms=bdms)
# TODO(stephenfin): Remove unused request_spec parameter in API v6.0
@wrap_exception()
@reverts_task_state
@wrap_instance_event(prefix='compute')
@errors_out_migration
@wrap_instance_fault
def finish_snapshot_based_resize_at_dest(
self, ctxt, instance, migration, snapshot_id, request_spec):
self, ctxt, instance, migration, snapshot_id):
"""Finishes the snapshot-based resize at the destination compute.
Sets up block devices and networking on the destination compute and
@ -5890,7 +5856,6 @@ class ComputeManager(manager.Manager):
be "finished".
:param snapshot_id: ID of the image snapshot created for a
non-volume-backed instance, else None.
:param request_spec: nova.objects.RequestSpec object for the operation
"""
LOG.info('Finishing snapshot based resize on destination host %s.',
self.host, instance=instance)
@ -6333,7 +6298,7 @@ class ComputeManager(manager.Manager):
@wrap_instance_event(prefix='compute')
@wrap_instance_fault
def shelve_instance(self, context, instance, image_id,
clean_shutdown, accel_uuids=None):
clean_shutdown, accel_uuids):
"""Shelve an instance.
This should be used when you want to take a snapshot of the instance.
@ -6418,7 +6383,7 @@ class ComputeManager(manager.Manager):
@wrap_instance_event(prefix='compute')
@wrap_instance_fault
def shelve_offload_instance(self, context, instance, clean_shutdown,
accel_uuids=None):
accel_uuids):
"""Remove a shelved instance from the hypervisor.
This frees up those resources for use by other instances, but may lead
@ -6509,9 +6474,8 @@ class ComputeManager(manager.Manager):
@reverts_task_state
@wrap_instance_event(prefix='compute')
@wrap_instance_fault
def unshelve_instance(
self, context, instance, image, filter_properties, node,
request_spec=None, accel_uuids=None):
def unshelve_instance(self, context, instance, image,
filter_properties, node, request_spec, accel_uuids):
"""Unshelve the instance.
:param context: request context
@ -6653,12 +6617,6 @@ class ComputeManager(manager.Manager):
self.host, action=fields.NotificationAction.UNSHELVE,
phase=fields.NotificationPhase.END, bdms=bdms)
# TODO(stephenfin): Remove this in RPC 6.0 since it's nova-network only
@messaging.expected_exceptions(NotImplementedError)
def reset_network(self, context, instance):
"""Reset networking on the given instance."""
raise NotImplementedError()
def _inject_network_info(self, instance, network_info):
"""Inject network info for the given instance."""
LOG.debug('Inject network info', instance=instance)
@ -7907,13 +7865,11 @@ class ComputeManager(manager.Manager):
return objects.ComputeNode.get_first_node_by_host_for_old_compat(
context, host)
# TODO(stephenfin): Remove the unused instance argument in RPC version 6.0
@wrap_exception()
def check_instance_shared_storage(self, ctxt, instance, data):
def check_instance_shared_storage(self, ctxt, data):
"""Check if the instance files are shared
:param ctxt: security context
:param instance: dict of instance data
:param data: result of driver.check_instance_shared_storage_local
Returns True if instance disks located on shared storage and
@ -7937,7 +7893,7 @@ class ComputeManager(manager.Manager):
@wrap_instance_fault
def check_can_live_migrate_destination(self, ctxt, instance,
block_migration, disk_over_commit,
migration=None, limits=None):
migration, limits):
"""Check if it is possible to execute live migration.
This runs checks on the destination host, and then calls
@ -8075,18 +8031,14 @@ class ComputeManager(manager.Manager):
LOG.debug('source check data is %s', result)
return result
# TODO(mriedem): Remove the block_migration argument in v6.0 of the compute
# RPC API.
@wrap_exception()
@wrap_instance_event(prefix='compute')
@wrap_instance_fault
def pre_live_migration(self, context, instance, block_migration, disk,
migrate_data):
def pre_live_migration(self, context, instance, disk, migrate_data):
"""Preparations for live migration at dest host.
:param context: security context
:param instance: dict of instance data
:param block_migration: if true, prepare for block migration
:param disk: disk info of instance
:param migrate_data: A dict or LiveMigrateData object holding data
required for live migration without shared
@ -10157,18 +10109,6 @@ class ComputeManager(manager.Manager):
# NOTE(mriedem): Why don't we pass clean_task_state=True here?
self._set_instance_obj_error_state(instance)
# TODO(stephenfin): Remove this once we bump the compute API to v6.0
@wrap_exception()
def add_aggregate_host(self, context, aggregate, host, slave_info):
"""(REMOVED) Notify hypervisor of change (for hypervisor pools)."""
raise NotImplementedError()
# TODO(stephenfin): Remove this once we bump the compute API to v6.0
@wrap_exception()
def remove_aggregate_host(self, context, host, slave_info, aggregate):
"""(REMOVED) Removes a host from a physical hypervisor pool."""
raise NotImplementedError()
def _process_instance_event(self, instance, event):
_event = self.instance_events.pop_instance_event(instance, event)
if _event:
@ -10714,3 +10654,144 @@ class ComputeManager(manager.Manager):
LOG.debug("Updating migrate VIF profile for port %(port_id)s:"
"%(profile)s", {'port_id': port_id,
'profile': profile})
# TODO(sbauza): Remove this proxy class in the X release once we drop the 5.x
# support.
# NOTE(sbauza): This proxy class will support the existing <=5.13 RPC calls
# from any RPC client but will also make sure that the new 6.0 RPC calls will
# be supported.
class _ComputeV5Proxy(object):
target = messaging.Target(version='5.13')
def __init__(self, manager):
self.manager = manager
def __getattr__(self, name):
# NOTE(sbauza): Proxying all the other methods but the V5 ones.
return getattr(self.manager, name)
# 5.0 support for block_migration argument
def pre_live_migration(self, context, instance, block_migration, disk,
migrate_data):
return self.manager.pre_live_migration(context, instance, disk,
migrate_data)
# 5.1 support for legacy request_spec argument
def prep_resize(self, context, image, instance, instance_type,
request_spec, filter_properties, node,
clean_shutdown, migration, host_list):
if not isinstance(request_spec, objects.RequestSpec):
# Prior to compute RPC API 5.1 conductor would pass a legacy dict
# version of the request spec to compute and since Stein compute
# could be sending that back to conductor on reschedule, so if we
# got a dict convert it to an object.
# TODO(mriedem): We can drop this compat code when we only support
# compute RPC API >=6.0.
request_spec = objects.RequestSpec.from_primitives(
context, request_spec, filter_properties)
# We don't have to set the new flavor on the request spec because
# if we got here it was due to a reschedule from the compute and
# the request spec would already have the new flavor in it from the
# else block below.
self.manager.prep_resize(context, image, instance, instance_type,
request_spec, filter_properties, node,
clean_shutdown, migration, host_list)
# 5.2 support for optional request_spec argument
def resize_instance(self, context, instance, image,
migration, instance_type, clean_shutdown,
request_spec=None):
self.manager.resize_instance(context, instance, image,
migration, instance_type, clean_shutdown,
request_spec)
# 5.2 support for optional request_spec argument
def finish_resize(self, context, disk_info, image, instance,
migration, request_spec=None):
self.manager.finish_resize(context, disk_info, image, instance,
migration, request_spec)
# 5.2 support for optional request_spec argument
def revert_resize(self, context, instance, migration, request_spec=None):
self.manager.revert_resize(context, instance, migration, request_spec)
# 5.2 support for optional request_spec argument
def finish_revert_resize(
self, context, instance, migration, request_spec=None):
self.manager.finish_revert_resize(context, instance, migration,
request_spec)
# 5.2 support for optional request_spec argument
# 5.13 support for optional accel_uuids argument
def unshelve_instance(self, context, instance, image, filter_properties,
node, request_spec=None, accel_uuids=None):
self.manager.unshelve_instance(context, instance, image,
filter_properties, node, request_spec,
accel_uuids or [])
# 5.3 support for optional migration and limits arguments
def check_can_live_migrate_destination(self, ctxt, instance,
block_migration, disk_over_commit,
migration=None, limits=None):
return self.manager.check_can_live_migrate_destination(
ctxt, instance, block_migration, disk_over_commit,
migration, limits)
# 5.11 support for optional accel_uuids argument
def build_and_run_instance(self, context, instance, image, request_spec,
filter_properties, admin_password=None,
injected_files=None, requested_networks=None,
security_groups=None, block_device_mapping=None,
node=None, limits=None, host_list=None, accel_uuids=None):
self.manager.build_and_run_instance(
context, instance, image, request_spec,
filter_properties, accel_uuids, admin_password,
injected_files, requested_networks,
security_groups, block_device_mapping,
node, limits, host_list)
# 5.12 support for optional accel_uuids argument
def rebuild_instance(self, context, instance, orig_image_ref, image_ref,
injected_files, new_pass, orig_sys_metadata,
bdms, recreate, on_shared_storage,
preserve_ephemeral, migration,
scheduled_node, limits, request_spec,
accel_uuids=None):
self.manager.rebuild_instance(
context, instance, orig_image_ref, image_ref,
injected_files, new_pass, orig_sys_metadata,
bdms, recreate, on_shared_storage,
preserve_ephemeral, migration,
scheduled_node, limits, request_spec,
accel_uuids)
# 5.13 support for optional accel_uuids argument
def shelve_instance(self, context, instance, image_id,
clean_shutdown, accel_uuids=None):
self.manager.shelve_instance(context, instance, image_id,
clean_shutdown, accel_uuids)
# 5.13 support for optional accel_uuids argument
def shelve_offload_instance(self, context, instance, clean_shutdown,
accel_uuids=None):
self.manager.shelve_offload_instance(
context, instance, clean_shutdown, accel_uuids)
# 6.0 drop unused request_spec argument
def prep_snapshot_based_resize_at_dest(
self, ctxt, instance, flavor, nodename, migration, limits,
request_spec):
return self.manager.prep_snapshot_based_resize_at_dest(
ctxt, instance, flavor, nodename, migration, limits)
# 6.0 drop unused request_spec argument
def finish_snapshot_based_resize_at_dest(
self, ctxt, instance, migration, snapshot_id, request_spec):
self.manager.finish_snapshot_based_resize_at_dest(
ctxt, instance, migration, snapshot_id)
# 6.0 drop unused instance argument
def check_instance_shared_storage(self, ctxt, instance, data):
return self.manager.check_instance_shared_storage(ctxt, data)

317
nova/compute/rpcapi.py

@ -383,6 +383,25 @@ class ComputeAPI(object):
* 5.13 - Add accel_uuids (accelerator requests) parameter to
shelve_instance(), shelve_offload_instance() and
unshelve_instance()
... Version 6.0 is functionally equivalent to 5.13, aside from
removing deprecated parameters and methods. Wallaby sends 6.0 by
default, can accept 5.x calls from Victoria nodes, and can be pinned to
5.x for Victoria compatibility. All new changes should go against 6.x.
* 6.0 - Remove 5.x compatibility
* ... - Remove add_aggregate_host()
* ... - Remove remove_aggregate_host()
* ... - Remove test_get_console_pool_info()
* ... - Remove test_get_console_topic()
* ... - Remove refresh_instance_security_rules()
* ... - Remove request_spec argument from
prep_snapshot_based_resize_at_dest() and
finish_snapshot_based_resize_at_dest()
* ... - Remove instance argument from check_instance_shared_storage()
* ... - Rename the instance_type argument of prep_resize() to flavor
* ... - Rename the instance_type argument of resize_instance() to
flavor
'''
VERSION_ALIASES = {
@ -400,6 +419,7 @@ class ComputeAPI(object):
'train': '5.3',
'ussuri': '5.11',
'victoria': '5.12',
'wallaby': '6.0',
}
@property
@ -414,7 +434,7 @@ class ComputeAPI(object):
if _ROUTER is None:
with lockutils.lock('compute-rpcapi-router'):
if _ROUTER is None:
target = messaging.Target(topic=RPC_TOPIC, version='5.0')
target = messaging.Target(topic=RPC_TOPIC, version='6.0')
upgrade_level = CONF.upgrade_levels.compute
if upgrade_level == 'auto':
version_cap = self._determine_version_cap(target)
@ -432,6 +452,22 @@ class ComputeAPI(object):
_ROUTER = rpc.ClientRouter(default_client)
return _ROUTER
def _ver(self, ctxt, old):
"""Determine compatibility version.
This is to be used when we could send either the current major or
a revision of the previous major when they are equivalent. This
should only be used by calls that are the exact same in the current
and previous major versions. Returns either old, or the current major
version.
:param old: The version under the previous major version that should
be sent if we're pinned to it.
"""
client = self.router.client(ctxt)
if client.can_send_version('6.0'):
return '6.0'
else:
return old
@staticmethod
def _determine_version_cap(target):
global LAST_VERSION
@ -515,26 +551,8 @@ class ComputeAPI(object):
serializer=serializer,
call_monitor_timeout=cmt)
# TODO(stephenfin): This is no longer used and can be removed in v6.0
def add_aggregate_host(self, ctxt, host, aggregate, host_param,
slave_info=None):
'''Add aggregate host.
:param ctxt: request context
:param aggregate:
:param host_param: This value is placed in the message to be the 'host'
parameter for the remote method.
:param host: This is the host to send the message to.
'''
version = '5.0'
cctxt = self.router.client(ctxt).prepare(
server=host, version=version)
cctxt.cast(ctxt, 'add_aggregate_host',
aggregate=aggregate, host=host_param,
slave_info=slave_info)
def add_fixed_ip_to_instance(self, ctxt, instance, network_id):
version = '5.0'
version = self._ver(ctxt, '5.0')
cctxt = self.router.client(ctxt).prepare(
server=_compute_host(None, instance), version=version)
cctxt.cast(ctxt, 'add_fixed_ip_to_instance',
@ -545,14 +563,14 @@ class ComputeAPI(object):
kw = {'instance': instance, 'network_id': network_id,
'port_id': port_id, 'requested_ip': requested_ip,
'tag': tag}
version = '5.0'
version = self._ver(ctxt, '5.0')
client = self.router.client(ctxt)
cctxt = client.prepare(server=_compute_host(None, instance),
version=version)
return cctxt.call(ctxt, 'attach_interface', **kw)
def attach_volume(self, ctxt, instance, bdm):
version = '5.0'
version = self._ver(ctxt, '5.0')
cctxt = self.router.client(ctxt).prepare(
server=_compute_host(None, instance), version=version)
cctxt.cast(ctxt, 'attach_volume', instance=instance, bdm=bdm)
@ -561,7 +579,7 @@ class ComputeAPI(object):
block_migration, disk_over_commit,
migration, limits):
client = self.router.client(ctxt)
version = '5.3'
version = self._ver(ctxt, '5.3')
kwargs = {
'instance': instance,
'block_migration': block_migration,
@ -579,7 +597,7 @@ class ComputeAPI(object):
return cctxt.call(ctxt, 'check_can_live_migrate_destination', **kwargs)
def check_can_live_migrate_source(self, ctxt, instance, dest_check_data):
version = '5.0'
version = self._ver(ctxt, '5.0')
client = self.router.client(ctxt)
source = _compute_host(None, instance)
cctxt = client.prepare(server=source, version=version)
@ -587,18 +605,22 @@ class ComputeAPI(object):
instance=instance,
dest_check_data=dest_check_data)
def check_instance_shared_storage(self, ctxt, instance, data, host=None):
version = '5.0'
cctxt = self.router.client(ctxt).prepare(
def check_instance_shared_storage(self, ctxt, data, instance=None,
host=None):
msg_args = {'data': data}
version = self._ver(ctxt, '5.0')
client = self.router.client(ctxt)
if not client.can_send_version('6.0'):
# We always pass the instance until the 5.0 version
msg_args['instance'] = instance
cctxt = client.prepare(
server=_compute_host(host, instance), version=version)
return cctxt.call(ctxt, 'check_instance_shared_storage',
instance=instance,
data=data)
return cctxt.call(ctxt, 'check_instance_shared_storage', **msg_args)
def confirm_resize(self, ctxt, instance, migration, host,
cast=True):
client = self.router.client(ctxt)
version = '5.0'
version = self._ver(ctxt, '5.0')
cctxt = client.prepare(
server=_compute_host(host, instance), version=version)
rpc_method = cctxt.cast if cast else cctxt.call
@ -628,7 +650,7 @@ class ComputeAPI(object):
:raises: oslo_messaging.exceptions.MessagingTimeout if the RPC call
times out
"""
version = '5.8'
version = self._ver(ctxt, '5.8')
client = self.router.client(ctxt)
if not client.can_send_version(version):
raise exception.MigrationError(reason=_('Compute too old'))
@ -641,14 +663,14 @@ class ComputeAPI(object):
instance=instance, migration=migration)
def detach_interface(self, ctxt, instance, port_id):
version = '5.0'
version = self._ver(ctxt, '5.0')
cctxt = self.router.client(ctxt).prepare(
server=_compute_host(None, instance), version=version)
cctxt.cast(ctxt, 'detach_interface',
instance=instance, port_id=port_id)
def detach_volume(self, ctxt, instance, volume_id, attachment_id=None):
version = '5.0'
version = self._ver(ctxt, '5.0')
client = self.router.client(ctxt)
cctxt = client.prepare(server=_compute_host(None, instance),
version=version)
@ -667,7 +689,7 @@ class ComputeAPI(object):
}
client = self.router.client(ctxt)
version = '5.2'
version = self._ver(ctxt, '5.2')
if not client.can_send_version(version):
msg_args.pop('request_spec')
@ -686,7 +708,7 @@ class ComputeAPI(object):
}
client = self.router.client(ctxt)
version = '5.2'
version = self._ver(ctxt, '5.2')
if not client.can_send_version(version):
msg_args.pop('request_spec')
@ -723,8 +745,13 @@ class ComputeAPI(object):
:raises: oslo_messaging.exceptions.MessagingTimeout if the pre-check
RPC call times out
"""
msg_args = {'instance': instance,
'migration': migration,
'snapshot_id': snapshot_id}
client = self.router.client(ctxt)
version = '5.7'
version = self._ver(ctxt, '5.7')
if not client.can_send_version('6.0'):
msg_args['request_spec'] = request_spec
if not client.can_send_version(version):
raise exception.MigrationError(reason=_('Compute too old'))
cctxt = client.prepare(
@ -732,9 +759,7 @@ class ComputeAPI(object):
call_monitor_timeout=CONF.rpc_response_timeout,
timeout=CONF.long_rpc_timeout)
return cctxt.call(
ctxt, 'finish_snapshot_based_resize_at_dest',
instance=instance, migration=migration, snapshot_id=snapshot_id,
request_spec=request_spec)
ctxt, 'finish_snapshot_based_resize_at_dest', **msg_args)
def finish_revert_snapshot_based_resize_at_source(
self, ctxt, instance, migration):
@ -759,7 +784,7 @@ class ComputeAPI(object):
:raises: oslo_messaging.exceptions.MessagingTimeout if the RPC call
times out
"""
version = '5.10'
version = self._ver(ctxt, '5.10')
client = self.router.client(ctxt)
if not client.can_send_version(version):
raise exception.MigrationError(reason=_('Compute too old'))
@ -772,77 +797,62 @@ class ComputeAPI(object):
instance=instance, migration=migration)
def get_console_output(self, ctxt, instance, tail_length):
version = '5.0'
version = self._ver(ctxt, '5.0')
cctxt = self.router.client(ctxt).prepare(
server=_compute_host(None, instance), version=version)
return cctxt.call(ctxt, 'get_console_output',
instance=instance, tail_length=tail_length)
# TODO(stephenfin): This is no longer used and can be removed in v6.0
def get_console_pool_info(self, ctxt, host, console_type):
version = '5.0'
cctxt = self.router.client(ctxt).prepare(
server=host, version=version)
return cctxt.call(ctxt, 'get_console_pool_info',
console_type=console_type)
# TODO(stephenfin): This is no longer used and can be removed in v6.0
def get_console_topic(self, ctxt, host):
version = '5.0'
cctxt = self.router.client(ctxt).prepare(
server=host, version=version)
return cctxt.call(ctxt, 'get_console_topic')
def get_diagnostics(self, ctxt, instance):
version = '5.0'
version = self._ver(ctxt, '5.0')
cctxt = self.router.client(ctxt).prepare(
server=_compute_host(None, instance), version=version)
return cctxt.call(ctxt, 'get_diagnostics', instance=instance)
def get_instance_diagnostics(self, ctxt, instance):
version = '5.0'
version = self._ver(ctxt, '5.0')
client = self.router.client(ctxt)
cctxt = client.prepare(server=_compute_host(None, instance),
version=version)
return cctxt.call(ctxt, 'get_instance_diagnostics', instance=instance)
def get_vnc_console(self, ctxt, instance, console_type):
version = '5.0'
version = self._ver(ctxt, '5.0')
cctxt = self.router.client(ctxt).prepare(
server=_compute_host(None, instance), version=version)
return cctxt.call(ctxt, 'get_vnc_console',
instance=instance, console_type=console_type)
def get_spice_console(self, ctxt, instance, console_type):
version = '5.0'
version = self._ver(ctxt, '5.0')
cctxt = self.router.client(ctxt).prepare(
server=_compute_host(None, instance), version=version)
return cctxt.call(ctxt, 'get_spice_console',
instance=instance, console_type=console_type)
def get_rdp_console(self, ctxt, instance, console_type):
version = '5.0'
version = self._ver(ctxt, '5.0')
cctxt = self.router.client(ctxt).prepare(
server=_compute_host(None, instance), version=version)
return cctxt.call(ctxt, 'get_rdp_console',
instance=instance, console_type=console_type)
def get_mks_console(self, ctxt, instance, console_type):
version = '5.0'
version = self._ver(ctxt, '5.0')
cctxt = self.router.client(ctxt).prepare(
server=_compute_host(None, instance), version=version)
return cctxt.call(ctxt, 'get_mks_console',
instance=instance, console_type=console_type)
def get_serial_console(self, ctxt, instance, console_type):
version = '5.0'
version = self._ver(ctxt, '5.0')
cctxt = self.router.client(ctxt).prepare(
server=_compute_host(None, instance), version=version)
return cctxt.call(ctxt, 'get_serial_console',
instance=instance, console_type=console_type)
def validate_console_port(self, ctxt, instance, port, console_type):
version = '5.0'
version = self._ver(ctxt, '5.0')
cctxt = self.router.client(ctxt).prepare(
server=_compute_host(None, instance), version=version)
return cctxt.call(ctxt, 'validate_console_port',
@ -858,27 +868,27 @@ class ComputeAPI(object):
:param mode:
:param host: This is the host to send the message to.
'''
version = '5.0'
version = self._ver(ctxt, '5.0')
cctxt = self.router.client(ctxt).prepare(
server=host, version=version)
return cctxt.call(ctxt, 'host_maintenance_mode',
host=host_param, mode=mode)
def host_power_action(self, ctxt, host, action):
version = '5.0'
version = self._ver(ctxt, '5.0')
cctxt = self.router.client(ctxt).prepare(
server=host, version=version)
return cctxt.call(ctxt, 'host_power_action', action=action)
def inject_network_info(self, ctxt, instance):
version = '5.0'
version = self._ver(ctxt, '5.0')
cctxt = self.router.client(ctxt).prepare(
server=_compute_host(None, instance), version=version)
cctxt.cast(ctxt, 'inject_network_info', instance=instance)
def live_migration(self, ctxt, instance, dest, block_migration, host,
migration, migrate_data=None):
version = '5.0'
version = self._ver(ctxt, '5.0')
client = self.router.client(ctxt)
cctxt = client.prepare(server=host, version=version)
cctxt.cast(ctxt, 'live_migration', instance=instance,
@ -886,7 +896,7 @@ class ComputeAPI(object):
migrate_data=migrate_data, migration=migration)
def live_migration_force_complete(self, ctxt, instance, migration):
version = '5.0'
version = self._ver(ctxt, '5.0')
client = self.router.client(ctxt)
cctxt = client.prepare(
server=_compute_host(migration.source_compute, instance),
@ -894,21 +904,21 @@ class ComputeAPI(object):
cctxt.cast(ctxt, 'live_migration_force_complete', instance=instance)
def live_migration_abort(self, ctxt, instance, migration_id):
version = '5.0'
version = self._ver(ctxt, '5.0')
cctxt = self.router.client(ctxt).prepare(
server=_compute_host(None, instance), version=version)
cctxt.cast(ctxt, 'live_migration_abort', instance=instance,
migration_id=migration_id)
def pause_instance(self, ctxt, instance):
version = '5.0'
version = self._ver(ctxt, '5.0')
cctxt = self.router.client(ctxt).prepare(
server=_compute_host(None, instance), version=version)
cctxt.cast(ctxt, 'pause_instance', instance=instance)
def post_live_migration_at_destination(self, ctxt, instance,
block_migration, host):
version = '5.0'
version = self._ver(ctxt, '5.0')
cctxt = self.router.client(ctxt).prepare(
server=host, version=version,
call_monitor_timeout=CONF.rpc_response_timeout,
@ -920,26 +930,32 @@ class ComputeAPI(object):
# the compute RPC API.
def pre_live_migration(self, ctxt, instance, block_migration, disk,
host, migrate_data):
version = '5.0'
version = '6.0'
msg_args = {}
client = self.router.client(ctxt)
if not client.can_send_version(version):
version = '5.0'
# We just need to honor the argument in the v5.0 RPC API method
msg_args['block_migration'] = None
cctxt = client.prepare(server=host, version=version,
timeout=CONF.long_rpc_timeout,
call_monitor_timeout=CONF.rpc_response_timeout)
return cctxt.call(ctxt, 'pre_live_migration',
instance=instance,
block_migration=block_migration,
disk=disk, migrate_data=migrate_data)
disk=disk, migrate_data=migrate_data,
**msg_args)
# TODO(mriedem): Drop compat for request_spec being a legacy dict in v6.0.
def prep_resize(self, ctxt, instance, image, instance_type, host,
def prep_resize(self, ctxt, instance, image, flavor, host,
migration, request_spec, filter_properties, node,
clean_shutdown, host_list):
version = '6.0'
# TODO(mriedem): We should pass the ImageMeta object through to the
# compute but that also requires plumbing changes through the resize
# flow for other methods like resize_instance and finish_resize.
image_p = objects_base.obj_to_primitive(image)
msg_args = {'instance': instance,
'instance_type': instance_type,
'flavor': flavor,
'image': image_p,
'request_spec': request_spec,
'filter_properties': filter_properties,
@ -948,11 +964,14 @@ class ComputeAPI(object):
'clean_shutdown': clean_shutdown,
'host_list': host_list}
client = self.router.client(ctxt)
version = '5.1'
if not client.can_send_version(version):
msg_args['request_spec'] = (
request_spec.to_legacy_request_spec_dict())
version = '5.0'
version = '5.1'
del msg_args['flavor']
msg_args['instance_type'] = flavor
if not client.can_send_version(version):
version = '5.0'
msg_args['request_spec'] = (
request_spec.to_legacy_request_spec_dict())
cctxt = client.prepare(server=host, version=version)
cctxt.cast(ctxt, 'prep_resize', **msg_args)
@ -990,17 +1009,22 @@ class ComputeAPI(object):
:raises: oslo_messaging.exceptions.MessagingTimeout if the pre-check
RPC call times out
"""
version = '5.5'
msg_args = {'instance': instance,
'flavor': flavor,
'nodename': nodename,
'migration': migration,
'limits': limits}
version = self._ver(ctxt, '5.5')
client = self.router.client(ctxt)
if not client.can_send_version('6.0'):
msg_args['request_spec'] = request_spec
if not client.can_send_version(version):
raise exception.MigrationPreCheckError(reason=_('Compute too old'))
cctxt = client.prepare(server=destination, version=version,
call_monitor_timeout=CONF.rpc_response_timeout,
timeout=CONF.long_rpc_timeout)
return cctxt.call(ctxt, 'prep_snapshot_based_resize_at_dest',
instance=instance, flavor=flavor, nodename=nodename,
migration=migration, limits=limits,
request_spec=request_spec)
**msg_args)
def prep_snapshot_based_resize_at_source(
self, ctxt, instance, migration, snapshot_id=None):
@ -1028,7 +1052,7 @@ class ComputeAPI(object):
:raises: oslo_messaging.exceptions.MessagingTimeout if the RPC call
times out
"""
version = '5.6'
version = self._ver(ctxt, '5.6')
client = self.router.client(ctxt)
if not client.can_send_version(version):
raise exception.MigrationError(reason=_('Compute too old'))
@ -1042,7 +1066,7 @@ class ComputeAPI(object):
def reboot_instance(self, ctxt, instance, block_device_info,
reboot_type):
version = '5.0'
version = self._ver(ctxt, '5.0')
cctxt = self.router.client(ctxt).prepare(
server=_compute_host(None, instance), version=version)
cctxt.cast(ctxt, 'reboot_instance',
@ -1068,7 +1092,7 @@ class ComputeAPI(object):
'request_spec': request_spec,
'accel_uuids': accel_uuids
}
version = '5.12'
version = self._ver(ctxt, '5.12')
client = self.router.client(ctxt)
if not client.can_send_version(version):
del msg_args['accel_uuids']
@ -1083,33 +1107,15 @@ class ComputeAPI(object):
recreate=recreate, on_shared_storage=on_shared_storage,
**msg_args)
# TODO(stephenfin): This is no longer used and can be removed in v6.0
def remove_aggregate_host(self, ctxt, host, aggregate, host_param,
slave_info=None):
'''Remove aggregate host.
:param ctxt: request context
:param aggregate:
:param host_param: This value is placed in the message to be the 'host'
parameter for the remote method.
:param host: This is the host to send the message to.
'''
version = '5.0'
cctxt = self.router.client(ctxt).prepare(
server=host, version=version)
cctxt.cast(ctxt, 'remove_aggregate_host',
aggregate=aggregate, host=host_param,
slave_info=slave_info)
def remove_fixed_ip_from_instance(self, ctxt, instance, address):
version = '5.0'
version = self._ver(ctxt, '5.0')
cctxt = self.router.client(ctxt).prepare(
server=_compute_host(None, instance), version=version)
cctxt.cast(ctxt, 'remove_fixed_ip_from_instance',
instance=instance, address=address)
def remove_volume_connection(self, ctxt, instance, volume_id, host):
version = '5.0'
version = self._ver(ctxt, '5.0')
cctxt = self.router.client(ctxt).prepare(
server=host, version=version)
return cctxt.call(ctxt, 'remove_volume_connection',
@ -1117,7 +1123,7 @@ class ComputeAPI(object):
def rescue_instance(self, ctxt, instance, rescue_password,
rescue_image_ref=None, clean_shutdown=True):
version = '5.0'
version = self._ver(ctxt, '5.0')
msg_args = {'rescue_password': rescue_password,
'clean_shutdown': clean_shutdown,
'rescue_image_ref': rescue_image_ref,
@ -1127,27 +1133,32 @@ class ComputeAPI(object):
server=_compute_host(None, instance), version=version)
cctxt.cast(ctxt, 'rescue_instance', **msg_args)
def resize_instance(self, ctxt, instance, migration, image, instance_type,
def resize_instance(self, ctxt, instance, migration, image, flavor,
request_spec, clean_shutdown=True):
version = '6.0'
msg_args = {'instance': instance, 'migration': migration,
'image': image,
'instance_type': instance_type,
'flavor': flavor,
'clean_shutdown': clean_shutdown,
'request_spec': request_spec,
}
version = '5.2'
client = self.router.client(ctxt)
if not client.can_send_version(version):
msg_args.pop('request_spec')
version = '5.0'
version = self._ver(ctxt, '5.2')
del msg_args['flavor']
msg_args['instance_type'] = flavor
if not client.can_send_version(version):
msg_args.pop('request_spec')
version = '5.0'
cctxt = client.prepare(server=_compute_host(None, instance),
version=version)
cctxt.cast(ctxt, 'resize_instance', **msg_args)
def resume_instance(self, ctxt, instance):
version = '5.0'
version = self._ver(ctxt, '5.0')
cctxt = self.router.client(ctxt).prepare(
server=_compute_host(None, instance), version=version)
cctxt.cast(ctxt, 'resume_instance', instance=instance)
@ -1161,7 +1172,7 @@ class ComputeAPI(object):
}
client = self.router.client(ctxt)
version = '5.2'
version = self._ver(ctxt, '5.2')
if not client.can_send_version(version):
msg_args.pop('request_spec')
@ -1190,7 +1201,7 @@ class ComputeAPI(object):
:raises: oslo_messaging.exceptions.MessagingTimeout if the RPC call
times out
"""
version = '5.9'
version = self._ver(ctxt, '5.9')
client = self.router.client(ctxt)
if not client.can_send_version(version):
raise exception.MigrationError(reason=_('Compute too old'))
@ -1205,18 +1216,20 @@ class ComputeAPI(object):
def rollback_live_migration_at_destination(self, ctxt, instance, host,
destroy_disks,
migrate_data):
version = '5.0'
version = self._ver(ctxt, '5.0')
client = self.router.client(ctxt)
cctxt = client.prepare(server=host, version=version)
cctxt.cast(ctxt, 'rollback_live_migration_at_destination',
instance=instance, destroy_disks=destroy_disks,
migrate_data=migrate_data)
# TODO(sbauza): Remove this when we bump the compute API to v6.0
def supports_numa_live_migration(self, ctxt):
"""Returns whether we can send 5.3, needed for NUMA live migration.
"""
client = self.router.client(ctxt)
return client.can_send_version('5.3')
version = self._ver(ctxt, '5.3')
return client.can_send_version(version)
def drop_move_claim_at_destination(self, ctxt, instance, host):
"""Called by the source of a live migration that's being rolled back.
@ -1227,20 +1240,20 @@ class ComputeAPI(object):
dropping the move claim before we drop the migration context from the
instance.
"""
version = '5.3'
version = self._ver(ctxt, '5.3')
client = self.router.client(ctxt)
cctxt = client.prepare(server=host, version=version)
cctxt.call(ctxt, 'drop_move_claim_at_destination', instance=instance)
def set_admin_password(self, ctxt, instance, new_pass):
version = '5.0'
version = self._ver(ctxt, '5.0')
cctxt = self.router.client(ctxt).prepare(
server=_compute_host(None, instance), version=version)
return cctxt.call(ctxt, 'set_admin_password',
instance=instance, new_pass=new_pass)
def set_host_enabled(self, ctxt, host, enabled):
version = '5.0'
version = self._ver(ctxt, '5.0')
cctxt = self.router.client(ctxt).prepare(
server=host, version=version,
call_monitor_timeout=CONF.rpc_response_timeout,
@ -1249,7 +1262,7 @@ class ComputeAPI(object):
def swap_volume(self, ctxt, instance, old_volume_id, new_volume_id,
new_attachment_id):
version = '5.0'
version = self._ver(ctxt, '5.0')
client = self.router.client(ctxt)
kwargs = dict(instance=instance,
old_volume_id=old_volume_id,
@ -1260,7 +1273,7 @@ class ComputeAPI(object):
cctxt.cast(ctxt, 'swap_volume', **kwargs)
def get_host_uptime(self, ctxt, host):
version = '5.0'
version = self._ver(ctxt, '5.0')
cctxt = self.router.client(ctxt).prepare(
server=host, version=version)
return cctxt.call(ctxt, 'get_host_uptime')
@ -1272,7 +1285,7 @@ class ComputeAPI(object):
'volume_id': volume_id, 'disk_bus': disk_bus,
'device_type': device_type, 'tag': tag,
'multiattach': multiattach}
version = '5.0'
version = self._ver(ctxt, '5.0')
client = self.router.client(ctxt)
cctxt = client.prepare(server=_compute_host(None, instance),
version=version,
@ -1282,7 +1295,7 @@ class ComputeAPI(object):
def backup_instance(self, ctxt, instance, image_id, backup_type,
rotation):
version = '5.0'
version = self._ver(ctxt, '5.0')
cctxt = self.router.client(ctxt).prepare(
server=_compute_host(None, instance), version=version)
cctxt.cast(ctxt, 'backup_instance',
@ -1292,7 +1305,7 @@ class ComputeAPI(object):
rotation=rotation)
def snapshot_instance(self, ctxt, instance, image_id):
version = '5.0'
version = self._ver(ctxt, '5.0')
cctxt = self.router.client(ctxt).prepare(
server=_compute_host(None, instance), version=version)
cctxt.cast(ctxt, 'snapshot_instance',
@ -1300,7 +1313,7 @@ class ComputeAPI(object):
image_id=image_id)
def start_instance(self, ctxt, instance):
version = '5.0'
version = self._ver(ctxt, '5.0')
cctxt = self.router.client(ctxt).prepare(
server=_compute_host(None, instance), version=version)
cctxt.cast(ctxt, 'start_instance', instance=instance)
@ -1308,46 +1321,46 @@ class ComputeAPI(object):
def stop_instance(self, ctxt, instance, do_cast=True, clean_shutdown=True):
msg_args = {'instance': instance,
'clean_shutdown': clean_shutdown}
version = '5.0'
version = self._ver(ctxt, '5.0')
cctxt = self.router.client(ctxt).prepare(
server=_compute_host(None, instance), version=version)
rpc_method = cctxt.cast if do_cast else cctxt.call
return rpc_method(ctxt, 'stop_instance', **msg_args)
def suspend_instance(self, ctxt, instance):
version = '5.0'
version = self._ver(ctxt, '5.0')
cctxt = self.router.client(ctxt).prepare(
server=_compute_host(None, instance), version=version)
cctxt.cast(ctxt, 'suspend_instance', instance=instance)
def terminate_instance(self, ctxt, instance, bdms):
client = self.router.client(ctxt)
version = '5.0'
version = self._ver(ctxt, '5.0')
cctxt = client.prepare(
server=_compute_host(None, instance), version=version)
cctxt.cast(ctxt, 'terminate_instance', instance=instance, bdms=bdms)
def unpause_instance(self, ctxt, instance):
version = '5.0'
version = self._ver(ctxt, '5.0')
cctxt = self.router.client(ctxt).prepare(
server=_compute_host(None, instance), version=version)
cctxt.cast(ctxt, 'unpause_instance', instance=instance)
def unrescue_instance(self, ctxt, instance):
version = '5.0'
version = self._ver(ctxt, '5.0')
cctxt = self.router.client(ctxt).prepare(
server=_compute_host(None, instance), version=version)
cctxt.cast(ctxt, 'unrescue_instance', instance=instance)
def soft_delete_instance(self, ctxt, instance):
client = self.router.client(ctxt)
version = '5.0'
version = self._ver(ctxt, '5.0')
cctxt = client.prepare(
server=_compute_host(None, instance), version=version)
cctxt.cast(ctxt, 'soft_delete_instance', instance=instance)
def restore_instance(self, ctxt, instance):
version = '5.0'
version = self._ver(ctxt, '5.0')
cctxt = self.router.client(ctxt).prepare(
server=_compute_host(None, instance), version=version)
cctxt.cast(ctxt, 'restore_instance', instance=instance)
@ -1361,7 +1374,7 @@ class ComputeAPI(object):
'accel_uuids': accel_uuids,
}
client = self.router.client(ctxt)
version = '5.13'
version = self._ver(ctxt, '5.13')
if not client.can_send_version(version):
if accel_uuids:
LOG.error("Shelve with accelerators is not supported as "
@ -1382,7 +1395,7 @@ class ComputeAPI(object):
'accel_uuids': accel_uuids,
}
client = self.router.client(ctxt)
version = '5.13'
version = self._ver(ctxt, '5.13')
if not client.can_send_version(version):
msg_kwargs.pop('accel_uuids')
version = '5.0'
@ -1392,7 +1405,7 @@ class ComputeAPI(object):
def unshelve_instance(self, ctxt, instance, host, request_spec, image=None,
filter_properties=None, node=None, accel_uuids=None):
version = '5.13'
version = self._ver(ctxt, '5.13')
msg_kwargs = {
'instance': instance,
'image': image,
@ -1416,7 +1429,7 @@ class ComputeAPI(object):
def volume_snapshot_create(self, ctxt, instance, volume_id,
create_info):