From 7c0e2238eb003ac0c620f4b63fa92baa6675e724 Mon Sep 17 00:00:00 2001 From: Dan Smith Date: Fri, 24 Jul 2015 12:14:00 -0700 Subject: [PATCH] Fix serializer supported version reporting in object_backport The serializer needs to report the version of the toplevel object that we were trying to deserialize when we encountered the incompatible version. We depend on the implementor of the indirection_api to use the object relationship mappings to return to us a fully-supported object tree based on the version at the top. This patch fixes the serializer to report the toplevel version instead of the one that caused the fault. Change-Id: I7ac03717e17cd7229abfeef6d9c7d9d8ec9be27a Closes-Bug: #1475356 --- nova/objects/base.py | 11 ++++++--- nova/tests/unit/objects/test_objects.py | 30 +++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/nova/objects/base.py b/nova/objects/base.py index 1466e2327085..7b4d3d8d62f9 100644 --- a/nova/objects/base.py +++ b/nova/objects/base.py @@ -632,7 +632,7 @@ class NovaObjectSerializer(messaging.NoOpSerializer): def _process_object(self, context, objprim): try: objinst = NovaObject.obj_from_primitive(objprim, context=context) - except exception.IncompatibleObjectVersion as e: + except exception.IncompatibleObjectVersion: objver = objprim['nova_object.version'] if objver.count('.') == 2: # NOTE(danms): For our purposes, the .z part of the version @@ -640,8 +640,13 @@ class NovaObjectSerializer(messaging.NoOpSerializer): objprim['nova_object.version'] = \ '.'.join(objver.split('.')[:2]) return self._process_object(context, objprim) - objinst = self.conductor.object_backport(context, objprim, - e.kwargs['supported']) + objname = objprim['nova_object.name'] + supported = NovaObjectRegistry.obj_classes().get(objname, []) + if supported: + objinst = self.conductor.object_backport(context, objprim, + supported[0].VERSION) + else: + raise return objinst def _process_iterable(self, context, action_fn, values): diff --git a/nova/tests/unit/objects/test_objects.py b/nova/tests/unit/objects/test_objects.py index d4feb87d6b47..42c942e4e97c 100644 --- a/nova/tests/unit/objects/test_objects.py +++ b/nova/tests/unit/objects/test_objects.py @@ -986,6 +986,36 @@ class TestObjectSerializer(_BaseTestCase): # .0 of the object. self.assertEqual('1.6', obj.VERSION) + def test_nested_backport(self): + @base.NovaObjectRegistry.register + class Parent(base.NovaObject): + VERSION = '1.0' + + fields = { + 'child': fields.ObjectField('MyObj'), + } + + @base.NovaObjectRegistry.register # noqa + class Parent(base.NovaObject): + VERSION = '1.1' + + fields = { + 'child': fields.ObjectField('MyObj'), + } + + child = MyObj(foo=1) + parent = Parent(child=child) + prim = parent.obj_to_primitive() + child_prim = prim['nova_object.data']['child'] + child_prim['nova_object.version'] = '1.10' + ser = base.NovaObjectSerializer() + with mock.patch.object(ser.conductor, 'object_backport') as backport: + ser.deserialize_entity(self.context, prim) + # NOTE(danms): This should be the version of the parent object, + # not the child. If wrong, this will be '1.6', which is the max + # child version in our registry. + backport.assert_called_once_with(self.context, prim, '1.1') + def test_object_serialization(self): ser = base.NovaObjectSerializer() obj = MyObj()