Use compatibility methods from oslo

This removes the nova mirrors of the compatibility and primitive
methods from oslo.versionedobjects. We needed to keep these until we
got on oslo's registry. We've done that, and now we need to drop these
so that we can take advantage of new features in oslo.

Related to bp/use-oslo-objects

Change-Id: I01aa967f524f80a2dfadee328cdbf55d0b96466b
This commit is contained in:
Dan Smith 2015-08-26 13:17:30 -07:00
parent 7a1ef0b538
commit 9fa632b455
7 changed files with 10 additions and 191 deletions

View File

@ -107,84 +107,6 @@ class NovaObject(ovoo_base.VersionedObject):
# version of the sub-object we know about
return self.obj_relationships[child][-1][1]
def _obj_make_obj_compatible(self, primitive, target_version, field):
"""Backlevel a sub-object based on our versioning rules.
This is responsible for backporting objects contained within
this object's primitive according to a set of rules we
maintain about version dependencies between objects. This
requires that the obj_relationships table in this object is
correct and up-to-date.
:param:primitive: The primitive version of this object
:param:target_version: The version string requested for this object
:param:field: The name of the field in this object containing the
sub-object to be backported
"""
def _do_backport(to_version):
obj = getattr(self, field)
if obj is None:
return
if isinstance(obj, NovaObject):
if to_version != primitive[field]['nova_object.version']:
obj.obj_make_compatible(
primitive[field]['nova_object.data'],
to_version)
primitive[field]['nova_object.version'] = to_version
elif isinstance(obj, list):
for i, element in enumerate(obj):
element.obj_make_compatible(
primitive[field][i]['nova_object.data'],
to_version)
primitive[field][i]['nova_object.version'] = to_version
child_version = self.obj_calculate_child_version(target_version, field)
if child_version is None:
del primitive[field]
else:
_do_backport(child_version)
def obj_make_compatible(self, primitive, target_version):
"""Make an object representation compatible with a target version.
This is responsible for taking the primitive representation of
an object and making it suitable for the given target_version.
This may mean converting the format of object attributes, removing
attributes that have been added since the target version, etc. In
general:
- If a new version of an object adds a field, this routine
should remove it for older versions.
- If a new version changed or restricted the format of a field, this
should convert it back to something a client knowing only of the
older version will tolerate.
- If an object that this object depends on is bumped, then this
object should also take a version bump. Then, this routine should
backlevel the dependent object (by calling its obj_make_compatible())
if the requested version of this object is older than the version
where the new dependent object was added.
:param:primitive: The result of self.obj_to_primitive()
:param:target_version: The version string requested by the recipient
of the object
:raises: nova.exception.UnsupportedObjectError if conversion
is not possible for some reason
"""
for key, field in self.fields.items():
if not isinstance(field, (obj_fields.ObjectField,
obj_fields.ListOfObjectsField)):
continue
if not self.obj_attr_is_set(key):
continue
if key not in self.obj_relationships:
# NOTE(danms): This is really a coding error and shouldn't
# happen unless we miss something
raise exception.ObjectActionError(
action='obj_make_compatible',
reason='No rule for %s' % key)
self._obj_make_obj_compatible(primitive, target_version, key)
# NOTE(danms): This has some minor change between the nova and o.vo
# version, so avoid inheriting it for the moment so we can make that
# transition separately for clarity.

View File

@ -55,6 +55,8 @@ SetOfIntegersField = fields.SetOfIntegersField
ListOfSetsOfIntegersField = fields.ListOfSetsOfIntegersField
ListOfDictOfNullableStringsField = fields.ListOfDictOfNullableStringsField
DictProxyField = fields.DictProxyField
ObjectField = fields.ObjectField
ListOfObjectsField = fields.ListOfObjectsField
# NOTE(danms): These are things we need to import for some of our
@ -67,6 +69,7 @@ FieldType = fields.FieldType
Set = fields.Set
Dict = fields.Dict
List = fields.List
Object = fields.Object
class Architecture(Enum):
@ -495,54 +498,6 @@ class IPV6Network(IPNetwork):
raise ValueError(six.text_type(e))
# FIXME(danms): Remove this after we convert to oslo.versionedobjects' registry
class Object(FieldType):
def __init__(self, obj_name, **kwargs):
self._obj_name = obj_name
super(Object, self).__init__(**kwargs)
def coerce(self, obj, attr, value):
try:
obj_name = value.obj_name()
except AttributeError:
obj_name = ""
if obj_name != self._obj_name:
raise ValueError(_('An object of type %(type)s is required '
'in field %(attr)s') %
{'type': self._obj_name, 'attr': attr})
return value
@staticmethod
def to_primitive(obj, attr, value):
return value.obj_to_primitive()
@staticmethod
def from_primitive(obj, attr, value):
# FIXME(danms): Avoid circular import from base.py
from nova.objects import base as obj_base
# NOTE (ndipanov): If they already got hydrated by the serializer, just
# pass them back unchanged
if isinstance(value, obj_base.NovaObject):
return value
return obj_base.NovaObject.obj_from_primitive(value, obj._context)
def describe(self):
return "Object<%s>" % self._obj_name
def stringify(self, value):
if 'uuid' in value.fields:
ident = '(%s)' % (value.obj_attr_is_set('uuid') and value.uuid or
'UNKNOWN')
elif 'id' in value.fields:
ident = '(%s)' % (value.obj_attr_is_set('id') and value.id or
'UNKNOWN')
else:
ident = ''
return '%s%s' % (self._obj_name, ident)
class NetworkModel(FieldType):
@staticmethod
def coerce(obj, attr, value):
@ -763,17 +718,3 @@ class NonNegativeFloatField(AutoTypedField):
class NonNegativeIntegerField(AutoTypedField):
AUTO_TYPE = NonNegativeInteger()
# FIXME(danms): Remove this after we convert to oslo.versionedobjects' registry
class ObjectField(AutoTypedField):
def __init__(self, objtype, **kwargs):
self.AUTO_TYPE = Object(objtype)
super(ObjectField, self).__init__(**kwargs)
# FIXME(danms): Remove this after we convert to oslo.versionedobjects' registry
class ListOfObjectsField(AutoTypedField):
def __init__(self, objtype, **kwargs):
self.AUTO_TYPE = List(Object(objtype))
super(ListOfObjectsField, self).__init__(**kwargs)

View File

@ -131,10 +131,10 @@ class InstanceNUMATopology(base.NovaObject,
}
@classmethod
def obj_from_primitive(cls, primitive):
def obj_from_primitive(cls, primitive, context=None):
if 'nova_object.name' in primitive:
obj_topology = super(InstanceNUMATopology, cls).obj_from_primitive(
primitive)
primitive, context=None)
else:
# NOTE(sahid): This compatibility code needs to stay until we can
# guarantee that there are no cases of the old format stored in

View File

@ -181,10 +181,10 @@ class NUMATopology(base.NovaObject,
}
@classmethod
def obj_from_primitive(cls, primitive):
def obj_from_primitive(cls, primitive, context=None):
if 'nova_object.name' in primitive:
obj_topology = super(NUMATopology, cls).obj_from_primitive(
primitive)
primitive, context=context)
else:
# NOTE(sahid): This compatibility code needs to stay until we can
# guarantee that there are no cases of the old format stored in

View File

@ -120,6 +120,7 @@ class Service(base.NovaPersistentObject, base.NovaObject,
self.version = SERVICE_VERSION
def obj_make_compatible(self, primitive, target_version):
super(Service, self).obj_make_compatible(primitive, target_version)
_target_version = utils.convert_version_to_tuple(target_version)
if _target_version < (1, 16) and 'version' in primitive:
del primitive['version']
@ -134,7 +135,6 @@ class Service(base.NovaPersistentObject, base.NovaObject,
# when called
self._do_compute_node(self._context, primitive,
target_compute_version)
super(Service, self).obj_make_compatible(primitive, target_version)
def _do_compute_node(self, context, primitive, target_version):
try:

View File

@ -21,7 +21,6 @@ from oslo_versionedobjects import exception as ovo_exc
import six
from nova.network import model as network_model
from nova.objects import base as obj_base
from nova.objects import fields
from nova import test
@ -834,43 +833,6 @@ class TestDictOfListOfStrings(TestField):
self.field.stringify({'foo': ['1', '2']}))
class TestObject(TestField):
def setUp(self):
super(TestObject, self).setUp()
class TestableObject(obj_base.NovaObject):
fields = {
'uuid': fields.StringField(),
}
def __eq__(self, value):
# NOTE(danms): Be rather lax about this equality thing to
# satisfy the assertEqual() in test_from_primitive(). We
# just want to make sure the right type of object is re-created
return value.__class__.__name__ == TestableObject.__name__
class OtherTestableObject(obj_base.NovaObject):
pass
obj_base.NovaObjectRegistry.register(TestableObject)
obj_base.NovaObjectRegistry.register(OtherTestableObject)
test_inst = TestableObject()
self._test_cls = TestableObject
self.field = fields.Field(fields.Object('TestableObject'))
self.coerce_good_values = [(test_inst, test_inst)]
self.coerce_bad_values = [OtherTestableObject(), 1, 'foo']
self.to_primitive_values = [(test_inst, test_inst.obj_to_primitive())]
self.from_primitive_values = [(test_inst.obj_to_primitive(),
test_inst),
(test_inst, test_inst)]
def test_stringify(self):
obj = self._test_cls(uuid='fake-uuid')
self.assertEqual('TestableObject(fake-uuid)',
self.field.stringify(obj))
class TestNetworkModel(TestField):
def setUp(self):
super(TestNetworkModel, self).setUp()

View File

@ -767,7 +767,8 @@ class _TestObject(object):
with mock.patch.object(subobj, 'obj_make_compatible') as mock_compat:
primitive = copy.deepcopy(orig_primitive)
obj._obj_make_obj_compatible(primitive, '1.7', 'rel_object')
self.assertFalse(mock_compat.called)
mock_compat.assert_called_once_with(
primitive['rel_object']['nova_object.data'], '1.2')
with mock.patch.object(subobj, 'obj_make_compatible') as mock_compat:
primitive = copy.deepcopy(orig_primitive)
@ -807,13 +808,6 @@ class _TestObject(object):
obj.obj_make_compatible({'rel_object': 'foo'}, '1.10')
self.assertFalse(mock_compat.called)
def test_obj_make_compatible_complains_about_missing_rules(self):
subobj = MyOwnedObject(baz=1)
obj = MyObj(foo=123, rel_object=subobj)
obj.obj_relationships = {}
self.assertRaises(exception.ObjectActionError,
obj.obj_make_compatible, {}, '1.0')
def test_obj_make_compatible_doesnt_skip_falsey_sub_objects(self):
@base.NovaObjectRegistry.register_if(False)
class MyList(base.ObjectListBase, base.NovaObject):