object-ify flavors manager side of the RPC

This change completes the conversion of flavors to use objects instead
of direct database access. The rpcapi sends objects for the new version
and primitivized data is sent for older versions.

Related to blueprint kilo-objects

Change-Id: Ib876f276cff99a21c5bca1c9f062a6c221a783e8
This commit is contained in:
melanie witt 2014-09-18 05:08:59 +00:00
parent 805e690372
commit 8a27da34e7
12 changed files with 88 additions and 44 deletions

View File

@ -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 '

View File

@ -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)

View File

@ -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):

View File

@ -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,

View File

@ -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]...

View File

@ -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'):

View File

@ -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)

View File

@ -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)

View File

@ -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"}

View File

@ -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):

View File

@ -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 {

View File

@ -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')