Teach conductor to do manifest-based object_class_action() things
This adds a new object_class_action_versions() handler in conductor, much like the manifest-aware backport method recently added. Since we back-convert object results from remotable_classmethod operations, we need to receive the version manifest there as well. Since oslo.versionedobjects doesn't currently pass that, we can do a little indirection in our rpcapi to start calling the new method, gathering the manifest first. Related to blueprint liberty-bump-object-and-rpcapi-versions Change-Id: I25751edee551304ec849d7b88e42624970fef45f
This commit is contained in:
parent
638a807686
commit
452053e8c7
|
@ -83,7 +83,7 @@ class ConductorManager(manager.Manager):
|
|||
namespace. See the ComputeTaskManager class for details.
|
||||
"""
|
||||
|
||||
target = messaging.Target(version='2.2')
|
||||
target = messaging.Target(version='2.3')
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(ConductorManager, self).__init__(service_name='conductor',
|
||||
|
@ -459,6 +459,20 @@ class ConductorManager(manager.Manager):
|
|||
return (result.obj_to_primitive(target_version=objver)
|
||||
if isinstance(result, nova_object.NovaObject) else result)
|
||||
|
||||
def object_class_action_versions(self, context, objname, objmethod,
|
||||
object_versions, args, kwargs):
|
||||
objclass = nova_object.NovaObject.obj_class_from_name(
|
||||
objname, object_versions[objname])
|
||||
args = tuple([context] + list(args))
|
||||
result = self._object_dispatch(objclass, objmethod, args, kwargs)
|
||||
# NOTE(danms): The RPC layer will convert to primitives for us,
|
||||
# but in this case, we need to honor the version the client is
|
||||
# asking for, so we do it before returning here.
|
||||
return (result.obj_to_primitive(
|
||||
target_version=object_versions[objname],
|
||||
version_manifest=object_versions)
|
||||
if isinstance(result, nova_object.NovaObject) else result)
|
||||
|
||||
def object_action(self, context, objinst, objmethod, args, kwargs):
|
||||
"""Perform an action on an object."""
|
||||
oldobj = objinst.obj_clone()
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
from oslo_config import cfg
|
||||
import oslo_messaging as messaging
|
||||
from oslo_serialization import jsonutils
|
||||
from oslo_versionedobjects import base as ovo_base
|
||||
|
||||
from nova.objects import base as objects_base
|
||||
from nova import rpc
|
||||
|
@ -185,6 +186,7 @@ class ConductorAPI(object):
|
|||
* Remove instance_update()
|
||||
|
||||
* 2.2 - Add object_backport_versions()
|
||||
* 2.3 - Add object_class_action_versions()
|
||||
"""
|
||||
|
||||
VERSION_ALIASES = {
|
||||
|
@ -215,11 +217,29 @@ class ConductorAPI(object):
|
|||
|
||||
def object_class_action(self, context, objname, objmethod, objver,
|
||||
args, kwargs):
|
||||
if self.client.can_send_version('2.3'):
|
||||
# NOTE(danms): If we're new enough, collect the object
|
||||
# version manifest and redirect the call to the newer
|
||||
# class action handler
|
||||
versions = ovo_base.obj_tree_get_versions(objname)
|
||||
return self.object_class_action_versions(context,
|
||||
objname,
|
||||
objmethod,
|
||||
versions,
|
||||
args, kwargs)
|
||||
cctxt = self.client.prepare()
|
||||
return cctxt.call(context, 'object_class_action',
|
||||
objname=objname, objmethod=objmethod,
|
||||
objver=objver, args=args, kwargs=kwargs)
|
||||
|
||||
def object_class_action_versions(self, context, objname, objmethod,
|
||||
object_versions, args, kwargs):
|
||||
cctxt = self.client.prepare(version='2.3')
|
||||
return cctxt.call(context, 'object_class_action_versions',
|
||||
objname=objname, objmethod=objmethod,
|
||||
object_versions=object_versions,
|
||||
args=args, kwargs=kwargs)
|
||||
|
||||
def object_action(self, context, objinst, objmethod, args, kwargs):
|
||||
cctxt = self.client.prepare()
|
||||
return cctxt.call(context, 'object_action', objinst=objinst,
|
||||
|
|
|
@ -395,6 +395,29 @@ class ConductorTestCase(_BaseTestCase, test.TestCase):
|
|||
self.assertIn('dict', updates)
|
||||
self.assertEqual({'foo': 'bar'}, updates['dict'])
|
||||
|
||||
def test_object_class_action_versions(self):
|
||||
@obj_base.NovaObjectRegistry.register
|
||||
class TestObject(obj_base.NovaObject):
|
||||
VERSION = '1.10'
|
||||
|
||||
@classmethod
|
||||
def foo(cls, context):
|
||||
return cls()
|
||||
|
||||
versions = {
|
||||
'TestObject': '1.2',
|
||||
'OtherObj': '1.0',
|
||||
}
|
||||
with mock.patch.object(self.conductor_manager,
|
||||
'_object_dispatch') as m:
|
||||
m.return_value = TestObject()
|
||||
m.return_value.obj_to_primitive = mock.MagicMock()
|
||||
self.conductor.object_class_action_versions(
|
||||
self.context, TestObject.obj_name(), 'foo', versions,
|
||||
tuple(), {})
|
||||
m.return_value.obj_to_primitive.assert_called_once_with(
|
||||
target_version='1.2', version_manifest=versions)
|
||||
|
||||
def _test_expected_exceptions(self, db_method, conductor_method, errors,
|
||||
*args, **kwargs):
|
||||
# Tests that expected exceptions are handled properly.
|
||||
|
|
Loading…
Reference in New Issue