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:
parent
7a1ef0b538
commit
9fa632b455
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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):
|
||||
|
|
Loading…
Reference in New Issue