Merge "Implement manifest-based backports"

This commit is contained in:
Jenkins 2015-09-03 05:08:45 +00:00 committed by Gerrit Code Review
commit 537f8a07f5
5 changed files with 85 additions and 22 deletions

View File

@ -70,6 +70,10 @@ class LocalAPI(object):
def object_backport(self, context, objinst, target_version):
return self._manager.object_backport(context, objinst, target_version)
def object_backport_versions(self, context, objinst, object_versions):
return self._manager.object_backport_versions(context, objinst,
object_versions)
class LocalComputeTaskAPI(object):
def __init__(self):

View File

@ -83,7 +83,7 @@ class ConductorManager(manager.Manager):
namespace. See the ComputeTaskManager class for details.
"""
target = messaging.Target(version='2.1')
target = messaging.Target(version='2.2')
def __init__(self, *args, **kwargs):
super(ConductorManager, self).__init__(service_name='conductor',
@ -482,6 +482,16 @@ class ConductorManager(manager.Manager):
def object_backport(self, context, objinst, target_version):
return objinst.obj_to_primitive(target_version=target_version)
def object_backport_versions(self, context, objinst, object_versions):
target = object_versions[objinst.obj_name()]
LOG.debug('Backporting %(obj)s to %(ver)s with versions %(manifest)s',
obj=objinst.obj_name(), ver=target,
manifest=','.join(
['%s=%s' % (name, ver)
for name, ver in object_versions.items()]))
return objinst.obj_to_primitive(target_version=target,
version_manifest=object_versions)
class ComputeTaskManager(base.Base):
"""Namespace for compute methods.

View File

@ -184,6 +184,7 @@ class ConductorAPI(object):
* Remove vol_usage_update()
* Remove instance_update()
* 2.2 - Add object_backport_versions()
"""
VERSION_ALIASES = {
@ -229,6 +230,11 @@ class ConductorAPI(object):
return cctxt.call(context, 'object_backport', objinst=objinst,
target_version=target_version)
def object_backport_versions(self, context, objinst, object_versions):
cctxt = self.client.prepare(version='2.2')
return cctxt.call(context, 'object_backport_versions', objinst=objinst,
object_versions=object_versions)
class ComputeTaskAPI(object):
"""Client side of the conductor 'compute' namespaced RPC API

View File

@ -306,10 +306,10 @@ class NovaObjectSerializer(messaging.NoOpSerializer):
'.'.join(objver.split('.')[:2])
return self._process_object(context, objprim)
objname = objprim['nova_object.name']
supported = NovaObjectRegistry.obj_classes().get(objname, [])
if supported:
objinst = self.conductor.object_backport(context, objprim,
supported[0].VERSION)
version_manifest = ovoo_base.obj_tree_get_versions(objname)
if objname in version_manifest:
objinst = self.conductor.object_backport_versions(
context, objprim, version_manifest)
else:
raise
return objinst

View File

@ -25,6 +25,7 @@ import fixtures
import mock
from oslo_log import log
from oslo_utils import timeutils
from oslo_versionedobjects import base as ovo_base
from oslo_versionedobjects import exception as ovo_exc
from oslo_versionedobjects import fixture
import six
@ -934,7 +935,7 @@ class TestObjectSerializer(_BaseTestCase):
my_version='1.6'):
ser = base.NovaObjectSerializer()
ser._conductor = mock.Mock()
ser._conductor.object_backport.return_value = 'backported'
ser._conductor.object_backport_versions.return_value = 'backported'
class MyTestObj(MyObj):
VERSION = my_version
@ -946,12 +947,12 @@ class TestObjectSerializer(_BaseTestCase):
primitive = obj.obj_to_primitive()
result = ser.deserialize_entity(self.context, primitive)
if backported_to is None:
self.assertFalse(ser._conductor.object_backport.called)
self.assertFalse(ser._conductor.object_backport_versions.called)
else:
self.assertEqual('backported', result)
ser._conductor.object_backport.assert_called_with(self.context,
primitive,
backported_to)
versions = ovo_base.obj_tree_get_versions('MyTestObj')
ser._conductor.object_backport_versions.assert_called_with(
self.context, primitive, versions)
def test_deserialize_entity_newer_version_backports(self):
self._test_deserialize_entity_newer('1.25', '1.6')
@ -983,13 +984,26 @@ class TestObjectSerializer(_BaseTestCase):
# .0 of the object.
self.assertEqual('1.6', obj.VERSION)
def test_nested_backport(self):
@mock.patch('oslo_versionedobjects.base.obj_tree_get_versions')
def test_object_tree_backport(self, mock_get_versions):
# Test the full client backport path all the way from the serializer
# to the conductor and back.
self.start_service('conductor',
manager='nova.conductor.manager.ConductorManager')
# NOTE(danms): Actually register a complex set of objects,
# two versions of the same parent object which contain a
# child sub object.
@base.NovaObjectRegistry.register
class Child(base.NovaObject):
VERSION = '1.10'
@base.NovaObjectRegistry.register
class Parent(base.NovaObject):
VERSION = '1.0'
fields = {
'child': fields.ObjectField('MyObj'),
'child': fields.ObjectField('Child'),
}
@base.NovaObjectRegistry.register # noqa
@ -997,21 +1011,50 @@ class TestObjectSerializer(_BaseTestCase):
VERSION = '1.1'
fields = {
'child': fields.ObjectField('MyObj'),
'child': fields.ObjectField('Child'),
}
child = MyObj(foo=1)
# NOTE(danms): Since we're on the same node as conductor,
# return a fake version manifest so that we confirm that it
# actually honors what the client asked for and not just what
# it sees in the local machine state.
mock_get_versions.return_value = {
'Parent': '1.0',
'Child': '1.5',
}
call_context = {}
real_ofp = base.NovaObject.obj_from_primitive
def fake_obj_from_primitive(*a, **k):
# NOTE(danms): We need the first call to this to report an
# incompatible object version, but subsequent calls must
# succeed. Since we're testing the backport path all the
# way through conductor and RPC, we can't fully break this
# method, we just need it to fail once to trigger the
# backport.
if 'run' in call_context:
return real_ofp(*a, **k)
else:
call_context['run'] = True
raise ovo_exc.IncompatibleObjectVersion('foo')
child = Child()
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')
with mock.patch('nova.objects.base.NovaObject.'
'obj_from_primitive') as mock_ofp:
mock_ofp.side_effect = fake_obj_from_primitive
result = ser.deserialize_entity(self.context, prim)
# Our newest version (and what we passed back) of Parent
# is 1.1, make sure that the manifest version is honored
self.assertEqual('1.0', result.VERSION)
# Our newest version (and what we passed back) of Child
# is 1.10, make sure that the manifest version is honored
self.assertEqual('1.5', result.child.VERSION)
def test_object_serialization(self):
ser = base.NovaObjectSerializer()