summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Lindgren <hanlind@kth.se>2016-06-29 20:29:47 +0200
committerLee Yarwood <lyarwood@redhat.com>2016-10-17 08:22:43 +0000
commit7b15ecc22fee0aa4d628a6e0d75850a3275bdaf6 (patch)
tree542582e9be1cd6297bb275fe54cd3734e9090548
parent8ad4ec4586cf1d5b3fdce13c986a290e7e63bc85 (diff)
Do not try to backport when db has older object version
Instance extras are stored as serialized objects in the database and because of this it is possible to get a version back that is older than what the client requested. This is in itself not a problem, but the way we do things right now in conductor we end up trying to backport to a newer version, which raises InvalidTargetVersion. This change adds a check to make sure we skip backporting if the requested version is newer than the actual db version as long as the major version is the same. Change-Id: I34ac0abd016b72d585f83ae2ce34790751082180 Closes-Bug: #1596119 (cherry picked from commit 1e3e7309997f90fbd0291c05cc859dd9ac0ef161)
Notes
Notes (review): Verified+1: Citrix XenServer CI Verified+1: Intel NFV CI <openstack-nfv-ci@intel.com> Code-Review+2: Dan Smith <dms@danplanet.com> Code-Review+1: Peter Hamilton <peter.hamilton@jhuapl.edu> Code-Review+2: Tony Breeds <tony@bakeyournoodle.com> Workflow+1: Tony Breeds <tony@bakeyournoodle.com> Verified+2: Jenkins Submitted-by: Jenkins Submitted-at: Tue, 18 Oct 2016 04:46:46 +0000 Reviewed-on: https://review.openstack.org/387249 Project: openstack/nova Branch: refs/heads/stable/newton
-rw-r--r--nova/conductor/manager.py20
-rw-r--r--nova/tests/unit/conductor/test_conductor.py50
2 files changed, 66 insertions, 4 deletions
diff --git a/nova/conductor/manager.py b/nova/conductor/manager.py
index 5f0591b..2e8b707 100644
--- a/nova/conductor/manager.py
+++ b/nova/conductor/manager.py
@@ -20,6 +20,7 @@ from oslo_config import cfg
20from oslo_log import log as logging 20from oslo_log import log as logging
21import oslo_messaging as messaging 21import oslo_messaging as messaging
22from oslo_utils import excutils 22from oslo_utils import excutils
23from oslo_utils import versionutils
23import six 24import six
24 25
25from nova.compute import rpcapi as compute_rpcapi 26from nova.compute import rpcapi as compute_rpcapi
@@ -96,10 +97,21 @@ class ConductorManager(manager.Manager):
96 # NOTE(danms): The RPC layer will convert to primitives for us, 97 # NOTE(danms): The RPC layer will convert to primitives for us,
97 # but in this case, we need to honor the version the client is 98 # but in this case, we need to honor the version the client is
98 # asking for, so we do it before returning here. 99 # asking for, so we do it before returning here.
99 return (result.obj_to_primitive( 100 # NOTE(hanlind): Do not convert older than requested objects,
100 target_version=object_versions[objname], 101 # see bug #1596119.
101 version_manifest=object_versions) 102 if isinstance(result, nova_object.NovaObject):
102 if isinstance(result, nova_object.NovaObject) else result) 103 target_version = object_versions[objname]
104 requested_version = versionutils.convert_version_to_tuple(
105 target_version)
106 actual_version = versionutils.convert_version_to_tuple(
107 result.VERSION)
108 do_backport = requested_version < actual_version
109 other_major_version = requested_version[0] != actual_version[0]
110 if do_backport or other_major_version:
111 result = result.obj_to_primitive(
112 target_version=target_version,
113 version_manifest=object_versions)
114 return result
103 115
104 def object_action(self, context, objinst, objmethod, args, kwargs): 116 def object_action(self, context, objinst, objmethod, args, kwargs):
105 """Perform an action on an object.""" 117 """Perform an action on an object."""
diff --git a/nova/tests/unit/conductor/test_conductor.py b/nova/tests/unit/conductor/test_conductor.py
index 2860088..398db59 100644
--- a/nova/tests/unit/conductor/test_conductor.py
+++ b/nova/tests/unit/conductor/test_conductor.py
@@ -22,6 +22,7 @@ import mock
22from mox3 import mox 22from mox3 import mox
23import oslo_messaging as messaging 23import oslo_messaging as messaging
24from oslo_utils import timeutils 24from oslo_utils import timeutils
25from oslo_versionedobjects import exception as ovo_exc
25import six 26import six
26 27
27from nova.compute import flavors 28from nova.compute import flavors
@@ -184,6 +185,55 @@ class ConductorTestCase(_BaseTestCase, test.TestCase):
184 m.return_value.obj_to_primitive.assert_called_once_with( 185 m.return_value.obj_to_primitive.assert_called_once_with(
185 target_version='1.2', version_manifest=versions) 186 target_version='1.2', version_manifest=versions)
186 187
188 def test_object_class_action_versions_old_object(self):
189 # Make sure we return older than requested objects unmodified,
190 # see bug #1596119.
191 @obj_base.NovaObjectRegistry.register
192 class TestObject(obj_base.NovaObject):
193 VERSION = '1.10'
194
195 @classmethod
196 def foo(cls, context):
197 return cls()
198
199 versions = {
200 'TestObject': '1.10',
201 'OtherObj': '1.0',
202 }
203 with mock.patch.object(self.conductor_manager,
204 '_object_dispatch') as m:
205 m.return_value = TestObject()
206 m.return_value.VERSION = '1.9'
207 m.return_value.obj_to_primitive = mock.MagicMock()
208 obj = self.conductor.object_class_action_versions(
209 self.context, TestObject.obj_name(), 'foo', versions,
210 tuple(), {})
211 self.assertFalse(m.return_value.obj_to_primitive.called)
212 self.assertEqual('1.9', obj.VERSION)
213
214 def test_object_class_action_versions_major_version_diff(self):
215 @obj_base.NovaObjectRegistry.register
216 class TestObject(obj_base.NovaObject):
217 VERSION = '2.10'
218
219 @classmethod
220 def foo(cls, context):
221 return cls()
222
223 versions = {
224 'TestObject': '2.10',
225 'OtherObj': '1.0',
226 }
227 with mock.patch.object(self.conductor_manager,
228 '_object_dispatch') as m:
229 m.return_value = TestObject()
230 m.return_value.VERSION = '1.9'
231 self.assertRaises(
232 ovo_exc.InvalidTargetVersion,
233 self.conductor.object_class_action_versions,
234 self.context, TestObject.obj_name(), 'foo', versions,
235 tuple(), {})
236
187 def test_reset(self): 237 def test_reset(self):
188 with mock.patch.object(objects.Service, 'clear_min_version_cache' 238 with mock.patch.object(objects.Service, 'clear_min_version_cache'
189 ) as mock_clear_cache: 239 ) as mock_clear_cache: