diff --git a/nova/compute/resource_tracker.py b/nova/compute/resource_tracker.py index e62d4eb56aec..3a1adaf2e2e6 100644 --- a/nova/compute/resource_tracker.py +++ b/nova/compute/resource_tracker.py @@ -35,7 +35,6 @@ from nova import exception from nova.i18n import _, _LI, _LW from nova import objects from nova.objects import base as obj_base -from nova.objects import instance as instance_obj from nova.pci import manager as pci_manager from nova.pci import whitelist as pci_whitelist from nova import rpc @@ -733,8 +732,7 @@ class ResourceTracker(object): is_deleted_instance = instance['vm_state'] == vm_states.DELETED if is_new_instance: - self.tracked_instances[uuid] = instance_obj.compat_instance( - instance) + self.tracked_instances[uuid] = obj_base.obj_to_primitive(instance) sign = 1 if is_deleted_instance: @@ -864,7 +862,7 @@ class ResourceTracker(object): """ usage = {} if isinstance(object_or_dict, objects.Instance): - usage = instance_obj.compat_instance(object_or_dict) + usage = obj_base.obj_to_primitive(object_or_dict) elif isinstance(object_or_dict, objects.Flavor): usage = obj_base.obj_to_primitive(object_or_dict) else: diff --git a/nova/objects/instance.py b/nova/objects/instance.py index 3274920a966b..fb3c1caa29a1 100644 --- a/nova/objects/instance.py +++ b/nova/objects/instance.py @@ -13,7 +13,6 @@ # under the License. import contextlib -import copy from oslo_config import cfg from oslo_db import exception as db_exc @@ -95,42 +94,6 @@ def _expected_cols(expected_attrs): return simple_cols + complex_cols -def compat_instance(instance): - """Create a dict-like instance structure from an objects.Instance. - - This is basically the same as nova.objects.base.obj_to_primitive(), - except that it includes some instance-specific details, like stashing - flavor information in system_metadata. - - If you have a function (or RPC client) that needs to see the instance - as a dict that has flavor information in system_metadata, use this - to appease it (while you fix said thing). - - :param instance: a nova.objects.Instance instance - :returns: a dict-based instance structure - """ - if not isinstance(instance, objects.Instance): - return instance - - db_instance = copy.deepcopy(base.obj_to_primitive(instance)) - - flavor_attrs = [('', 'flavor'), ('old_', 'old_flavor'), - ('new_', 'new_flavor')] - for prefix, attr in flavor_attrs: - flavor = (instance.obj_attr_is_set(attr) and - getattr(instance, attr) or None) - if flavor: - # NOTE(danms): If flavor is unset or None, don't - # copy it into the primitive's system_metadata - db_instance['system_metadata'] = \ - flavors.save_flavor_info( - db_instance.get('system_metadata', {}), - flavor, prefix) - if attr in db_instance: - del db_instance[attr] - return db_instance - - # TODO(berrange): Remove NovaObjectDictCompat @base.NovaObjectRegistry.register class Instance(base.NovaPersistentObject, base.NovaObject, diff --git a/nova/scheduler/utils.py b/nova/scheduler/utils.py index d8d27c207e87..cc18807f35d1 100644 --- a/nova/scheduler/utils.py +++ b/nova/scheduler/utils.py @@ -29,7 +29,6 @@ from nova import exception from nova.i18n import _, _LE, _LW from nova import objects from nova.objects import base as obj_base -from nova.objects import instance as instance_obj from nova import rpc @@ -63,10 +62,24 @@ def build_request_spec(ctxt, image, instances, instance_type=None): instance_type = flavors.extract_flavor(instance) if isinstance(instance, objects.Instance): - instance = instance_obj.compat_instance(instance) + instance = obj_base.obj_to_primitive(instance) + # obj_to_primitive doesn't copy this enough, so be sure + # to detach our metadata blob because we modify it below. + instance['system_metadata'] = dict(instance.get('system_metadata', {})) if isinstance(instance_type, objects.Flavor): instance_type = obj_base.obj_to_primitive(instance_type) + # NOTE(danms): Replicate this old behavior because the + # scheduler RPC interface technically expects it to be + # there. Remove this when we bump the scheduler RPC API to + # v5.0 + try: + flavors.save_flavor_info(instance.get('system_metadata', {}), + instance_type) + except KeyError: + # If the flavor isn't complete (which is legit with a + # flavor object, just don't put it in the request spec + pass request_spec = { 'image': image or {}, diff --git a/nova/tests/unit/conductor/test_conductor.py b/nova/tests/unit/conductor/test_conductor.py index 94fcfb93e2ab..396c5b64b72f 100644 --- a/nova/tests/unit/conductor/test_conductor.py +++ b/nova/tests/unit/conductor/test_conductor.py @@ -45,7 +45,6 @@ from nova import objects from nova.objects import base as obj_base from nova.objects import block_device as block_device_obj from nova.objects import fields -from nova.objects import instance as instance_obj from nova.objects import quotas as quotas_obj from nova import quota from nova import rpc @@ -1042,7 +1041,9 @@ class _BaseTaskTestCase(object): uuid=uuid.uuid4(), flavor=instance_type) for i in range(2)] instance_type_p = obj_base.obj_to_primitive(instance_type) - instance_properties = instance_obj.compat_instance(instances[0]) + instance_properties = obj_base.obj_to_primitive(instances[0]) + instance_properties['system_metadata'] = flavors.save_flavor_info( + {}, instance_type) self.mox.StubOutWithMock(scheduler_utils, 'setup_instance_group') self.mox.StubOutWithMock(self.conductor_manager.scheduler_client, diff --git a/nova/tests/unit/objects/test_instance.py b/nova/tests/unit/objects/test_instance.py index 94b97ee52316..5ee6cf001106 100644 --- a/nova/tests/unit/objects/test_instance.py +++ b/nova/tests/unit/objects/test_instance.py @@ -1700,21 +1700,3 @@ class TestInstanceObjectMisc(test.TestCase): self.assertEqual(['metadata', 'extra', 'extra.numa_topology'], instance._expected_cols(['metadata', 'numa_topology'])) - - def test_compat_instance(self): - inst = objects.Instance(id=123) - inst.flavor = flavors.get_default_flavor() - inst.old_flavor = flavors.get_default_flavor() - inst.new_flavor = None - db_inst = instance.compat_instance(inst) - self.assertEqual(inst.id, db_inst['id']) - self.assertEqual(inst.flavor.flavorid, - db_inst['system_metadata']['instance_type_flavorid']) - self.assertEqual(inst.old_flavor.flavorid, - db_inst['system_metadata']['old_instance_type_flavorid']) - self.assertNotIn('new_instance_type_id', - db_inst['system_metadata']) - - def test_compat_instance_noninstance(self): - self.assertEqual(mock.sentinel.noninstance, - instance.compat_instance(mock.sentinel.noninstance)) diff --git a/nova/tests/unit/virt/test_hardware.py b/nova/tests/unit/virt/test_hardware.py index aaf4bbe38a33..186e0f6021cb 100644 --- a/nova/tests/unit/virt/test_hardware.py +++ b/nova/tests/unit/virt/test_hardware.py @@ -22,7 +22,6 @@ from nova import context from nova import exception from nova import objects from nova.objects import base as base_obj -from nova.objects import instance as instance_obj from nova.pci import stats from nova import test from nova.virt import hardware as hw @@ -1658,7 +1657,7 @@ class HelperMethodsTestCase(test.NoDBTestCase): fake_uuid = str(uuid.uuid4()) instance = objects.Instance(context=self.context, id=1, uuid=fake_uuid, numa_topology=self.instancetopo) - instance_dict = instance_obj.compat_instance(instance) + instance_dict = base_obj.obj_to_primitive(instance) instance_numa_topo = hw.instance_topology_from_instance(instance_dict) for expected_cell, actual_cell in zip(self.instancetopo.cells, instance_numa_topo.cells):