diff --git a/nova/cells/manager.py b/nova/cells/manager.py index 3faea8024380..d8f4d3bc9770 100644 --- a/nova/cells/manager.py +++ b/nova/cells/manager.py @@ -73,7 +73,7 @@ class CellsManager(manager.Manager): Scheduling requests get passed to the scheduler class. """ - target = oslo_messaging.Target(version='1.29') + target = oslo_messaging.Target(version='1.30') def __init__(self, *args, **kwargs): LOG.warning(_LW('The cells feature of Nova is considered experimental ' diff --git a/nova/cells/rpcapi.py b/nova/cells/rpcapi.py index 9a398504d7da..162468b8da16 100644 --- a/nova/cells/rpcapi.py +++ b/nova/cells/rpcapi.py @@ -101,6 +101,8 @@ class CellsAPI(object): ... Juno supports message version 1.29. So, any changes to existing methods in 1.x after that point should be done such that they can handle the version_cap being set to 1.29. + + * 1.30 - Make build_instances() use flavor object ''' VERSION_ALIASES = { @@ -150,11 +152,15 @@ class CellsAPI(object): build_inst_kwargs['instances'] = instances_p build_inst_kwargs['image'] = jsonutils.to_primitive( build_inst_kwargs['image']) - if 'filter_properties' in build_inst_kwargs: - flavor = build_inst_kwargs['filter_properties']['instance_type'] - flavor_p = objects_base.obj_to_primitive(flavor) - build_inst_kwargs['filter_properties']['instance_type'] = flavor_p - cctxt = self.client.prepare(version='1.8') + version = '1.30' + if not self.client.can_send_version(version): + version = '1.8' + if 'filter_properties' in build_inst_kwargs: + filter_properties = build_inst_kwargs['filter_properties'] + flavor = filter_properties['instance_type'] + flavor_p = objects_base.obj_to_primitive(flavor) + filter_properties['instance_type'] = flavor_p + cctxt = self.client.prepare(version=version) cctxt.cast(ctxt, 'build_instances', build_inst_kwargs=build_inst_kwargs) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index f240709e654c..f2f782c4e1ec 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -587,7 +587,7 @@ class ComputeVirtAPI(virtapi.VirtAPI): class ComputeManager(manager.Manager): """Manages the running instances from creation to destruction.""" - target = messaging.Target(version='3.35') + target = messaging.Target(version='3.36') # How long to wait in seconds before re-issuing a shutdown # signal to a instance during power off. The overall @@ -1994,6 +1994,13 @@ class ComputeManager(manager.Manager): requested_networks = objects.NetworkRequestList( objects=[objects.NetworkRequest.from_tuple(t) for t in requested_networks]) + # NOTE(melwitt): Remove this in v4.0 of the RPC API + flavor = filter_properties.get('instance_type') + if flavor and not isinstance(flavor, objects.Flavor): + # Code downstream may expect extra_specs to be populated since it + # is receiving an object, so lookup the flavor to ensure this. + flavor = objects.Flavor.get_by_id(context, flavor['id']) + filter_properties = dict(filter_properties, instance_type=flavor) @utils.synchronized(instance.uuid) def _locked_do_build_and_run_instance(*args, **kwargs): diff --git a/nova/compute/rpcapi.py b/nova/compute/rpcapi.py index a2c5b62b2602..1c5d2fa5dcbf 100644 --- a/nova/compute/rpcapi.py +++ b/nova/compute/rpcapi.py @@ -274,6 +274,8 @@ class ComputeAPI(object): ... Juno supports message version 3.35. So, any changes to existing methods in 3.x after that point should be done such that they can handle the version_cap being set to 3.35. + + * 3.36 - Make build_and_run_instance() send a Flavor object ''' VERSION_ALIASES = { @@ -880,17 +882,20 @@ class ComputeAPI(object): filter_properties, admin_password=None, injected_files=None, requested_networks=None, security_groups=None, block_device_mapping=None, node=None, limits=None): - version = '3.33' + version = '3.36' + if not self.client.can_send_version(version): + version = '3.33' + if 'instance_type' in filter_properties: + flavor = filter_properties['instance_type'] + flavor_p = objects_base.obj_to_primitive(flavor) + filter_properties = dict(filter_properties, + instance_type=flavor_p) if not self.client.can_send_version(version): version = '3.23' if requested_networks is not None: requested_networks = [(network_id, address, port_id) for (network_id, address, port_id, _) in requested_networks.as_tuples()] - if 'instance_type' in filter_properties: - flavor = filter_properties['instance_type'] - flavor_p = objects_base.obj_to_primitive(flavor) - filter_properties = dict(filter_properties, instance_type=flavor_p) cctxt = self.client.prepare(server=host, version=version) cctxt.cast(ctxt, 'build_and_run_instance', instance=instance, diff --git a/nova/conductor/manager.py b/nova/conductor/manager.py index 8fe6aea33d51..e39be2938d7e 100644 --- a/nova/conductor/manager.py +++ b/nova/conductor/manager.py @@ -461,7 +461,7 @@ class ComputeTaskManager(base.Base): may involve coordinating activities on multiple compute nodes. """ - target = messaging.Target(namespace='compute_task', version='1.9') + target = messaging.Target(namespace='compute_task', version='1.10') def __init__(self): super(ComputeTaskManager, self).__init__() @@ -491,6 +491,11 @@ class ComputeTaskManager(base.Base): instance = objects.Instance._from_db_object( context, objects.Instance(), instance, expected_attrs=attrs) + # NOTE(melwitt): Remove this in version 2.0 of the RPC API + if flavor and not isinstance(flavor, objects.Flavor): + # Code downstream may expect extra_specs to be populated since it + # is receiving an object, so lookup the flavor to ensure this. + flavor = objects.Flavor.get_by_id(context, flavor['id']) if live and not rebuild and not flavor: self._live_migrate(context, instance, scheduler_hint, block_migration, disk_over_commit) @@ -545,11 +550,6 @@ class ComputeTaskManager(base.Base): # context is not serializable filter_properties.pop('context', None) - # TODO(timello): originally, instance_type in request_spec - # on compute.api.resize does not have 'extra_specs', so we - # remove it for now to keep tests backward compatibility. - request_spec['instance_type'].pop('extra_specs', None) - (host, node) = (host_state['host'], host_state['nodename']) self.compute_rpcapi.prep_resize( context, image, instance, @@ -622,6 +622,13 @@ class ComputeTaskManager(base.Base): requested_networks = objects.NetworkRequestList( objects=[objects.NetworkRequest.from_tuple(t) for t in requested_networks]) + # TODO(melwitt): Remove this in version 2.0 of the RPC API + flavor = filter_properties.get('instance_type') + if flavor and not isinstance(flavor, objects.Flavor): + # Code downstream may expect extra_specs to be populated since it + # is receiving an object, so lookup the flavor to ensure this. + flavor = objects.Flavor.get_by_id(context, flavor['id']) + filter_properties = dict(filter_properties, instance_type=flavor) try: # check retry policy. Rather ugly use of instances[0]... diff --git a/nova/conductor/rpcapi.py b/nova/conductor/rpcapi.py index e0b01fe6ca93..60621742d0fe 100644 --- a/nova/conductor/rpcapi.py +++ b/nova/conductor/rpcapi.py @@ -390,6 +390,7 @@ class ComputeTaskAPI(object): 1.7 - Do not send block_device_mapping and legacy_bdm to build_instances 1.8 - Add rebuild_instance 1.9 - Converted requested_networks to NetworkRequestList object + 1.10 - Made migrate_server() and build_instances() send flavor objects """ @@ -404,17 +405,18 @@ class ComputeTaskAPI(object): def migrate_server(self, context, instance, scheduler_hint, live, rebuild, flavor, block_migration, disk_over_commit, reservations=None): - if self.client.can_send_version('1.6'): + version = '1.10' + if not self.client.can_send_version(version): + flavor = objects_base.obj_to_primitive(flavor) version = '1.6' - else: + if not self.client.can_send_version(version): instance = jsonutils.to_primitive( objects_base.obj_to_primitive(instance)) version = '1.4' - flavor_p = jsonutils.to_primitive(flavor) cctxt = self.client.prepare(version=version) return cctxt.call(context, 'migrate_server', instance=instance, scheduler_hint=scheduler_hint, - live=live, rebuild=rebuild, flavor=flavor_p, + live=live, rebuild=rebuild, flavor=flavor, block_migration=block_migration, disk_over_commit=disk_over_commit, reservations=reservations) @@ -423,19 +425,21 @@ class ComputeTaskAPI(object): admin_password, injected_files, requested_networks, security_groups, block_device_mapping, legacy_bdm=True): image_p = jsonutils.to_primitive(image) - if 'instance_type' in filter_properties: - flavor = filter_properties['instance_type'] - flavor_p = objects_base.obj_to_primitive(flavor) - filter_properties = dict(filter_properties, instance_type=flavor_p) + version = '1.10' + if not self.client.can_send_version(version): + version = '1.9' + if 'instance_type' in filter_properties: + flavor = filter_properties['instance_type'] + flavor_p = objects_base.obj_to_primitive(flavor) + filter_properties = dict(filter_properties, + instance_type=flavor_p) kw = {'instances': instances, 'image': image_p, 'filter_properties': filter_properties, 'admin_password': admin_password, 'injected_files': injected_files, 'requested_networks': requested_networks, 'security_groups': security_groups} - - version = '1.9' - if not self.client.can_send_version('1.9'): + if not self.client.can_send_version(version): version = '1.8' kw['requested_networks'] = kw['requested_networks'].as_tuples() if not self.client.can_send_version('1.7'): diff --git a/nova/scheduler/manager.py b/nova/scheduler/manager.py index aae2c81b26ca..f24abadb1772 100644 --- a/nova/scheduler/manager.py +++ b/nova/scheduler/manager.py @@ -60,7 +60,7 @@ QUOTAS = quota.QUOTAS class SchedulerManager(manager.Manager): """Chooses a host to run instances on.""" - target = messaging.Target(version='3.0') + target = messaging.Target(version='3.1') def __init__(self, scheduler_driver=None, *args, **kwargs): if not scheduler_driver: @@ -171,6 +171,13 @@ class SchedulerManager(manager.Manager): The result should be a list of dicts with 'host', 'nodename' and 'limits' as keys. """ + # TODO(melwitt): Remove this in version 4.0 of the RPC API + flavor = filter_properties.get('instance_type') + if flavor and not isinstance(flavor, objects.Flavor): + # Code downstream may expect extra_specs to be populated since it + # is receiving an object, so lookup the flavor to ensure this. + flavor = objects.Flavor.get_by_id(context, flavor['id']) + filter_properties = dict(filter_properties, instance_type=flavor) dests = self.driver.select_destinations(context, request_spec, filter_properties) return jsonutils.to_primitive(dests) diff --git a/nova/scheduler/rpcapi.py b/nova/scheduler/rpcapi.py index 131bbe76e544..902af8661cb8 100644 --- a/nova/scheduler/rpcapi.py +++ b/nova/scheduler/rpcapi.py @@ -84,6 +84,8 @@ class SchedulerAPI(object): existing methods in 3.x after that point should be done such that they can handle the version_cap being set to 3.0. + * 3.1 - Made select_destinations() send flavor object + ''' VERSION_ALIASES = { @@ -103,10 +105,14 @@ class SchedulerAPI(object): serializer=serializer) def select_destinations(self, ctxt, request_spec, filter_properties): - if 'instance_type' in filter_properties: - flavor = filter_properties['instance_type'] - flavor_p = objects_base.obj_to_primitive(flavor) - filter_properties = dict(filter_properties, instance_type=flavor_p) - cctxt = self.client.prepare() + version = '3.1' + if not self.client.can_send_version(version): + version = '3.0' + if 'instance_type' in filter_properties: + flavor = filter_properties['instance_type'] + flavor_p = objects_base.obj_to_primitive(flavor) + filter_properties = dict(filter_properties, + instance_type=flavor_p) + cctxt = self.client.prepare(version=version) return cctxt.call(ctxt, 'select_destinations', request_spec=request_spec, filter_properties=filter_properties) diff --git a/nova/tests/unit/cells/test_cells_rpcapi.py b/nova/tests/unit/cells/test_cells_rpcapi.py index 398b96d8aef2..2d7ee74c293c 100644 --- a/nova/tests/unit/cells/test_cells_rpcapi.py +++ b/nova/tests/unit/cells/test_cells_rpcapi.py @@ -135,7 +135,7 @@ class CellsAPITestCase(test.NoDBTestCase): 'arg2': 2, 'arg3': 3}} self._check_result(call_info, 'build_instances', - expected_args, version='1.8') + expected_args, version='1.30') def test_get_capacities(self): capacity_info = {"capacity": "info"} diff --git a/nova/tests/unit/compute/test_rpcapi.py b/nova/tests/unit/compute/test_rpcapi.py index bf8e41215e9a..cc9be4492c61 100644 --- a/nova/tests/unit/compute/test_rpcapi.py +++ b/nova/tests/unit/compute/test_rpcapi.py @@ -468,7 +468,7 @@ class ComputeRpcAPITestCase(test.TestCase): admin_password='passwd', injected_files=None, requested_networks=['network1'], security_groups=None, block_device_mapping=None, node='node', limits=[], - version='3.33') + version='3.36') @mock.patch('nova.utils.is_neutron', return_value=True) def test_build_and_run_instance_icehouse_compat(self, is_neutron): diff --git a/nova/tests/unit/conductor/test_conductor.py b/nova/tests/unit/conductor/test_conductor.py index 92a86813a9b6..d30173c28560 100644 --- a/nova/tests/unit/conductor/test_conductor.py +++ b/nova/tests/unit/conductor/test_conductor.py @@ -1196,9 +1196,9 @@ class _BaseTaskTestCase(object): inst = fake_instance.fake_db_instance(image_ref='image_ref') inst_obj = objects.Instance._from_db_object( self.context, objects.Instance(), inst, []) - flavor = obj_base.obj_to_primitive(flavors.get_default_flavor()) - flavor['extra_specs'] = 'extra_specs' - request_spec = {'instance_type': flavor, + flavor = flavors.get_default_flavor() + flavor.extra_specs = {'extra_specs': 'fake'} + request_spec = {'instance_type': obj_base.obj_to_primitive(flavor), 'instance_properties': {}} compute_utils.get_image_metadata( self.context, self.conductor_manager.image_api, @@ -1207,7 +1207,7 @@ class _BaseTaskTestCase(object): scheduler_utils.build_request_spec( self.context, 'image', [mox.IsA(objects.Instance)], - instance_type=flavor).AndReturn(request_spec) + instance_type=mox.IsA(objects.Flavor)).AndReturn(request_spec) scheduler_utils.setup_instance_group(self.context, request_spec, {}) @@ -1222,7 +1222,7 @@ class _BaseTaskTestCase(object): self.conductor_manager.compute_rpcapi.prep_resize( self.context, 'image', mox.IsA(objects.Instance), - mox.IsA(dict), 'host1', [], request_spec=request_spec, + mox.IsA(objects.Flavor), 'host1', [], request_spec=request_spec, filter_properties=filter_properties, node=None) self.mox.ReplayAll() @@ -1630,8 +1630,9 @@ class ConductorTaskTestCase(_BaseTaskTestCase, test_compute.BaseTestCase): self.context, None, None, True, True, None, None, None) def test_migrate_server_fails_with_flavor(self): + flavor = flavors.get_flavor_by_name('m1.tiny') self.assertRaises(NotImplementedError, self.conductor.migrate_server, - self.context, None, None, True, False, "dummy", None, None) + self.context, None, None, True, False, flavor, None, None) def _build_request_spec(self, instance): return { diff --git a/nova/tests/unit/scheduler/test_rpcapi.py b/nova/tests/unit/scheduler/test_rpcapi.py index 381e81deebc8..b3d6c37a2289 100644 --- a/nova/tests/unit/scheduler/test_rpcapi.py +++ b/nova/tests/unit/scheduler/test_rpcapi.py @@ -66,4 +66,5 @@ class SchedulerRpcAPITestCase(test.NoDBTestCase): def test_select_destinations(self): self._test_scheduler_api('select_destinations', rpc_method='call', request_spec='fake_request_spec', - filter_properties='fake_prop') + filter_properties='fake_prop', + version='3.1')