Remove references to Nova

Remove remaining references to "Nova" where possible, code cleanup.
Also removed IP fields

Co-Authored-By: Michal Jastrzebski (inc0) <michal.jastrzebski@intel.com>
Change-Id: Ibad8f9fc6453321055029ad69b0374261509b9d5
Closes-Bug: 1417287
This commit is contained in:
Grzegorz Grasza
2015-02-03 11:52:41 +01:00
committed by Dan Smith
parent 5e79ffca1d
commit c330f938c8
10 changed files with 179 additions and 403 deletions

View File

@@ -24,36 +24,4 @@ def register_all():
# NOTE(danms): You must make sure your object gets imported in this
# function in order for it to be registered by services that may
# need to receive it via RPC.
__import__('nova.objects.agent')
__import__('nova.objects.aggregate')
__import__('nova.objects.bandwidth_usage')
__import__('nova.objects.block_device')
__import__('nova.objects.compute_node')
__import__('nova.objects.dns_domain')
__import__('nova.objects.ec2')
__import__('nova.objects.external_event')
__import__('nova.objects.fixed_ip')
__import__('nova.objects.flavor')
__import__('nova.objects.floating_ip')
__import__('nova.objects.hv_spec')
__import__('nova.objects.instance')
__import__('nova.objects.instance_action')
__import__('nova.objects.instance_fault')
__import__('nova.objects.instance_group')
__import__('nova.objects.instance_info_cache')
__import__('nova.objects.instance_numa_topology')
__import__('nova.objects.instance_pci_requests')
__import__('nova.objects.keypair')
__import__('nova.objects.migration')
__import__('nova.objects.network')
__import__('nova.objects.network_request')
__import__('nova.objects.numa')
__import__('nova.objects.pci_device')
__import__('nova.objects.pci_device_pool')
__import__('nova.objects.tag')
__import__('nova.objects.quotas')
__import__('nova.objects.security_group')
__import__('nova.objects.security_group_rule')
__import__('nova.objects.service')
__import__('nova.objects.virt_cpu_topology')
__import__('nova.objects.virtual_interface')
pass

View File

@@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
"""Nova common internal object model"""
"""Common internal object model"""
import collections
import contextlib
@@ -159,13 +159,13 @@ def remotable_classmethod(fn):
"""Decorator for remotable classmethods."""
@functools.wraps(fn)
def wrapper(cls, context, *args, **kwargs):
if NovaObject.indirection_api:
result = NovaObject.indirection_api.object_class_action(
if VersionedObject.indirection_api:
result = VersionedObject.indirection_api.object_class_action(
context, cls.obj_name(), fn.__name__, cls.VERSION,
args, kwargs)
else:
result = fn(cls, context, *args, **kwargs)
if isinstance(result, NovaObject):
if isinstance(result, VersionedObject):
result._context = context
return result
@@ -188,16 +188,16 @@ def remotable(fn):
if ctxt is None:
raise exception.OrphanedObjectError(method=fn.__name__,
objtype=self.obj_name())
if NovaObject.indirection_api:
updates, result = NovaObject.indirection_api.object_action(
if VersionedObject.indirection_api:
updates, result = VersionedObject.indirection_api.object_action(
ctxt, self, fn.__name__, args, kwargs)
for key, value in updates.iteritems():
if key in self.fields:
field = self.fields[key]
# NOTE(ndipanov): Since NovaObjectSerializer will have
# NOTE(ndipanov): Since VersionedObjectSerializer will have
# deserialized any object fields into objects already,
# we do not try to deserialize them again here.
if isinstance(value, NovaObject):
if isinstance(value, VersionedObject):
self[key] = value
else:
self[key] = field.from_primitive(self, key, value)
@@ -212,7 +212,7 @@ def remotable(fn):
return wrapper
class NovaObject(object):
class VersionedObject(object):
"""Base class and object factory.
This forms the base of all objects that can be remoted or instantiated
@@ -327,8 +327,8 @@ class NovaObject(object):
self = cls()
self._context = context
self.VERSION = objver
objdata = primitive['nova_object.data']
changes = primitive.get('nova_object.changes', [])
objdata = primitive['versioned_object.data']
changes = primitive.get('versioned_object.changes', [])
for name, field in self.fields.items():
if name in objdata:
setattr(self, name, field.from_primitive(self, name,
@@ -339,14 +339,14 @@ class NovaObject(object):
@classmethod
def obj_from_primitive(cls, primitive, context=None):
"""Object field-by-field hydration."""
if primitive['nova_object.namespace'] != 'nova':
if primitive['versioned_object.namespace'] != 'versionedobjects':
# NOTE(danms): We don't do anything with this now, but it's
# there for "the future"
raise exception.UnsupportedObjectError(
objtype='%s.%s' % (primitive['nova_object.namespace'],
primitive['nova_object.name']))
objname = primitive['nova_object.name']
objver = primitive['nova_object.version']
objtype='%s.%s' % (primitive['versioned_object.namespace'],
primitive['versioned_object.name']))
objname = primitive['versioned_object.name']
objver = primitive['versioned_object.version']
objclass = cls.obj_class_from_name(objname, objver)
return objclass._obj_from_primitive(context, objver, primitive)
@@ -391,17 +391,18 @@ class NovaObject(object):
obj = getattr(self, field)
if not obj:
return
if isinstance(obj, NovaObject):
if isinstance(obj, VersionedObject):
obj.obj_make_compatible(
primitive[field]['nova_object.data'],
primitive[field]['versioned_object.data'],
to_version)
primitive[field]['nova_object.version'] = to_version
primitive[field]['versioned_object.version'] = to_version
elif isinstance(obj, list):
for i, element in enumerate(obj):
element.obj_make_compatible(
primitive[field][i]['nova_object.data'],
primitive[field][i]['versioned_object.data'],
to_version)
primitive[field][i]['nova_object.version'] = to_version
primitive[field][i][
'versioned_object.version'] = to_version
target_version = utils.convert_version_to_tuple(target_version)
for index, versions in enumerate(self.obj_relationships[field]):
@@ -448,8 +449,8 @@ class NovaObject(object):
: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
:raises: oslo_versionedobjects.exception.UnsupportedObjectError
if conversion is not possible for some reason
"""
for key, field in self.fields.items():
if not isinstance(field, (fields.ObjectField,
@@ -477,12 +478,12 @@ class NovaObject(object):
getattr(self, name))
if target_version:
self.obj_make_compatible(primitive, target_version)
obj = {'nova_object.name': self.obj_name(),
'nova_object.namespace': 'nova',
'nova_object.version': target_version or self.VERSION,
'nova_object.data': primitive}
obj = {'versioned_object.name': self.obj_name(),
'versioned_object.namespace': 'versionedobjects',
'versioned_object.version': target_version or self.VERSION,
'versioned_object.data': primitive}
if self.obj_what_changed():
obj['nova_object.changes'] = list(self.obj_what_changed())
obj['versioned_object.changes'] = list(self.obj_what_changed())
return obj
def obj_set_defaults(self, *attrs):
@@ -520,7 +521,7 @@ class NovaObject(object):
changes = set(self._changed_fields)
for field in self.fields:
if (self.obj_attr_is_set(field) and
isinstance(getattr(self, field), NovaObject) and
isinstance(getattr(self, field), VersionedObject) and
getattr(self, field).obj_what_changed()):
changes.add(field)
return changes
@@ -560,7 +561,7 @@ class NovaObject(object):
return self.fields.keys() + self.obj_extra_fields
class NovaObjectDictCompat(object):
class VersionedObjectDictCompat(object):
"""Mix-in to provide dictionary key access compat
If an object needs to support attribute access using
@@ -631,7 +632,7 @@ class NovaObjectDictCompat(object):
setattr(self, key, value)
class NovaPersistentObject(object):
class VersionedPersistentObject(object):
"""Mixin class for Persistent objects.
This adds the fields that we use in common for all persistent objects.
"""
@@ -675,7 +676,7 @@ class ObjectListBase(object):
serialization of the list of objects automatically.
"""
fields = {
'objects': fields.ListOfObjectsField('NovaObject'),
'objects': fields.ListOfObjectsField('VersionedObject'),
}
# This is a dictionary of my_version:child_version mappings so that
@@ -702,7 +703,7 @@ class ObjectListBase(object):
if isinstance(index, slice):
new_obj = self.__class__()
new_obj.objects = self.objects[index]
# NOTE(danms): We must be mixed in with a NovaObject!
# NOTE(danms): We must be mixed in with a VersionedObject!
new_obj.obj_reset_changes()
new_obj._context = self._context
return new_obj
@@ -728,9 +729,10 @@ class ObjectListBase(object):
child_target_version = self.child_versions.get(target_version, '1.0')
for index, item in enumerate(self.objects):
self.objects[index].obj_make_compatible(
primitives[index]['nova_object.data'],
primitives[index]['versioned_object.data'],
child_target_version)
primitives[index]['nova_object.version'] = child_target_version
primitives[index][
'versioned_object.version'] = child_target_version
def obj_what_changed(self):
changes = set(self._changed_fields)
@@ -740,13 +742,13 @@ class ObjectListBase(object):
return changes
class NovaObjectSerializer(messaging.NoOpSerializer):
"""A NovaObject-aware Serializer.
class VersionedObjectSerializer(messaging.NoOpSerializer):
"""A VersionedObject-aware Serializer.
This implements the Oslo Serializer interface and provides the
ability to serialize and deserialize NovaObject entities. Any service
that needs to accept or return NovaObjects as arguments or result values
should pass this to its RPCClient and RPCServer objects.
ability to serialize and deserialize VersionedObject entities. Any service
that needs to accept or return VersionedObjects as arguments or result
values should pass this to its RPCClient and RPCServer objects.
"""
@property
@@ -758,13 +760,14 @@ class NovaObjectSerializer(messaging.NoOpSerializer):
def _process_object(self, context, objprim):
try:
objinst = NovaObject.obj_from_primitive(objprim, context=context)
objinst = VersionedObject.obj_from_primitive(
objprim, context=context)
except exception.IncompatibleObjectVersion as e:
objver = objprim['nova_object.version']
objver = objprim['versioned_object.version']
if objver.count('.') == 2:
# NOTE(danms): For our purposes, the .z part of the version
# should be safe to accept without requiring a backport
objprim['nova_object.version'] = \
objprim['versioned_object.version'] = \
'.'.join(objver.split('.')[:2])
return self._process_object(context, objprim)
objinst = self.conductor.object_backport(context, objprim,
@@ -803,7 +806,7 @@ class NovaObjectSerializer(messaging.NoOpSerializer):
return entity
def deserialize_entity(self, context, entity):
if isinstance(entity, dict) and 'nova_object.name' in entity:
if isinstance(entity, dict) and 'versioned_object.name' in entity:
entity = self._process_object(context, entity)
elif isinstance(entity, (tuple, list, set, dict)):
entity = self._process_iterable(context, self.deserialize_entity,
@@ -814,12 +817,12 @@ class NovaObjectSerializer(messaging.NoOpSerializer):
def obj_to_primitive(obj):
"""Recursively turn an object into a python primitive.
A NovaObject becomes a dict, and anything that implements ObjectListBase
becomes a list.
A VersionedObject becomes a dict, and anything that implements
ObjectListBase becomes a list.
"""
if isinstance(obj, ObjectListBase):
return [obj_to_primitive(x) for x in obj]
elif isinstance(obj, NovaObject):
elif isinstance(obj, VersionedObject):
result = {}
for key in obj.obj_fields:
if obj.obj_attr_is_set(key) or key in obj.obj_extra_fields:
@@ -841,7 +844,7 @@ def obj_make_list(context, list_obj, item_cls, db_list, **extra_args):
:param:context: Request context
:param:list_obj: An ObjectListBase object
:param:item_cls: The NovaObject class of the objects within the list
:param:item_cls: The VersionedObject class of the objects within the list
:param:db_list: The list of primitives to convert to objects
:param:extra_args: Extra arguments to pass to _from_db_object()
:returns: list_obj

View File

@@ -14,9 +14,9 @@
# License for the specific language governing permissions and limitations
# under the License.
"""Nova base exception handling.
"""VersionedObjects base exception handling.
Includes decorator for re-raising Nova-type exceptions.
Includes decorator for re-raising VersionedObjects-type exceptions.
SHOULD include dedicated exception logging.
@@ -91,8 +91,8 @@ def wrap_exception(notifier=None, get_notifier=None):
return inner
class NovaException(Exception):
"""Base Nova Exception
class VersionedObjectsException(Exception):
"""Base VersionedObjects Exception
To correctly use this class, inherit from it and define
a 'msg_fmt' property. That msg_fmt will get printf'd
@@ -131,33 +131,34 @@ class NovaException(Exception):
# at least get the core message out if something happened
message = self.msg_fmt
super(NovaException, self).__init__(message)
super(VersionedObjectsException, self).__init__(message)
def format_message(self):
# NOTE(mrodden): use the first argument to the python Exception object
# which should be our full NovaException message, (see __init__)
# which should be our full VersionedObjectsException message,
# (see __init__)
return self.args[0]
class ObjectActionError(NovaException):
class ObjectActionError(VersionedObjectsException):
msg_fmt = _('Object action %(action)s failed because: %(reason)s')
class ObjectFieldInvalid(NovaException):
class ObjectFieldInvalid(VersionedObjectsException):
msg_fmt = _('Field %(field)s of %(objname)s is not an instance of Field')
class OrphanedObjectError(NovaException):
class OrphanedObjectError(VersionedObjectsException):
msg_fmt = _('Cannot call %(method)s on orphaned %(objtype)s object')
class IncompatibleObjectVersion(NovaException):
class IncompatibleObjectVersion(VersionedObjectsException):
msg_fmt = _('Version %(objver)s of %(objname)s is not supported')
class ReadOnlyFieldError(NovaException):
class ReadOnlyFieldError(VersionedObjectsException):
msg_fmt = _('Cannot modify readonly field %(field)s')
class UnsupportedObjectError(NovaException):
class UnsupportedObjectError(VersionedObjectsException):
msg_fmt = _('Unsupported object type %(objtype)s')

109
oslo_versionedobjects/fields.py Normal file → Executable file
View File

@@ -16,7 +16,6 @@ import abc
import datetime
import iso8601
import netaddr
from oslo_utils import timeutils
import six
@@ -54,7 +53,7 @@ class AbstractFieldType(object):
This method should convert the value given into the designated type,
or throw an exception if this is not possible.
:param:obj: The NovaObject on which an attribute is being set
:param:obj: The VersionedObject on which an attribute is being set
:param:attr: The name of the attribute being set
:param:value: The value being set
:returns: A properly-typed value
@@ -68,7 +67,7 @@ class AbstractFieldType(object):
This method should deserialize a value from the form given by
to_primitive() to the designated type.
:param:obj: The NovaObject on which the value is to be set
:param:obj: The VersionedObject on which the value is to be set
:param:attr: The name of the attribute which will hold the value
:param:value: The serialized form of the value
:returns: The natural form of the value
@@ -82,7 +81,7 @@ class AbstractFieldType(object):
This method should serialize a value to the form expected by
from_primitive().
:param:obj: The NovaObject on which the value is set
:param:obj: The VersionedObject on which the value is set
:param:attr: The name of the attribute holding the value
:param:value: The natural form of the value
:returns: The serialized form of the value
@@ -304,76 +303,6 @@ class DateTime(FieldType):
return timeutils.isotime(value)
class IPAddress(FieldType):
@staticmethod
def coerce(obj, attr, value):
try:
return netaddr.IPAddress(value)
except netaddr.AddrFormatError as e:
raise ValueError(six.text_type(e))
def from_primitive(self, obj, attr, value):
return self.coerce(obj, attr, value)
@staticmethod
def to_primitive(obj, attr, value):
return str(value)
class IPV4Address(IPAddress):
@staticmethod
def coerce(obj, attr, value):
result = IPAddress.coerce(obj, attr, value)
if result.version != 4:
raise ValueError(_('Network "%s" is not valid') % value)
return result
class IPV6Address(IPAddress):
@staticmethod
def coerce(obj, attr, value):
result = IPAddress.coerce(obj, attr, value)
if result.version != 6:
raise ValueError(_('Network "%s" is not valid') % value)
return result
class IPV4AndV6Address(IPAddress):
@staticmethod
def coerce(obj, attr, value):
result = IPAddress.coerce(obj, attr, value)
if result.version != 4 and result.version != 6:
raise ValueError(_('Network "%s" is not valid') % value)
return result
class IPNetwork(IPAddress):
@staticmethod
def coerce(obj, attr, value):
try:
return netaddr.IPNetwork(value)
except netaddr.AddrFormatError as e:
raise ValueError(six.text_type(e))
class IPV4Network(IPNetwork):
@staticmethod
def coerce(obj, attr, value):
try:
return netaddr.IPNetwork(value, version=4)
except netaddr.AddrFormatError as e:
raise ValueError(six.text_type(e))
class IPV6Network(IPNetwork):
@staticmethod
def coerce(obj, attr, value):
try:
return netaddr.IPNetwork(value, version=6)
except netaddr.AddrFormatError as e:
raise ValueError(six.text_type(e))
class CompoundFieldType(FieldType):
def __init__(self, element_type, **field_args):
self._element_type = Field(element_type, **field_args)
@@ -517,9 +446,9 @@ class Object(FieldType):
from oslo_versionedobjects 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):
if isinstance(value, obj_base.VersionedObject):
return value
return obj_base.NovaObject.obj_from_primitive(value, obj._context)
return obj_base.VersionedObject.obj_from_primitive(value, obj._context)
def describe(self):
return "Object<%s>" % self._obj_name
@@ -568,34 +497,6 @@ class DateTimeField(AutoTypedField):
AUTO_TYPE = DateTime()
class IPAddressField(AutoTypedField):
AUTO_TYPE = IPAddress()
class IPV4AddressField(AutoTypedField):
AUTO_TYPE = IPV4Address()
class IPV6AddressField(AutoTypedField):
AUTO_TYPE = IPV6Address()
class IPV4AndV6AddressField(AutoTypedField):
AUTO_TYPE = IPV4AndV6Address()
class IPNetworkField(AutoTypedField):
AUTO_TYPE = IPNetwork()
class IPV4NetworkField(AutoTypedField):
AUTO_TYPE = IPV4Network()
class IPV6NetworkField(AutoTypedField):
AUTO_TYPE = IPV6Network()
class DictOfStringsField(AutoTypedField):
AUTO_TYPE = Dict(String())

View File

@@ -51,7 +51,7 @@ CONF = cfg.CONF
# CONF.set_override('use_stderr', False)
logging.register_options(CONF)
logging.setup(CONF, 'nova')
logging.setup(CONF, 'versionedobjects')
# NOTE(comstud): Make sure we have all of the objects loaded. We do this
# at module import time, because we may be using mock decorators in our

View File

@@ -14,7 +14,7 @@
# License for the specific language governing permissions and limitations
# under the License.
"""Fixtures for Nova tests."""
"""Fixtures for VersionedObject tests."""
from __future__ import absolute_import
import gettext
@@ -44,7 +44,7 @@ class ServiceFixture(fixtures.Fixture):
name = name
host = host or uuid.uuid4().hex
kwargs.setdefault('host', host)
kwargs.setdefault('binary', 'nova-%s' % name)
kwargs.setdefault('binary', 'versionedobjects-%s' % name)
self.kwargs = kwargs
def setUp(self):

90
oslo_versionedobjects/tests/test_fields.py Normal file → Executable file
View File

@@ -15,7 +15,6 @@
import datetime
import iso8601
import netaddr
from oslo_utils import timeutils
from oslo_versionedobjects import base as obj_base
@@ -133,49 +132,6 @@ class TestDateTime(TestField):
tzinfo=iso8601.iso8601.Utc())))
class TestIPAddress(TestField):
def setUp(self):
super(TestIPAddress, self).setUp()
self.field = fields.IPAddressField()
self.coerce_good_values = [('1.2.3.4', netaddr.IPAddress('1.2.3.4')),
('::1', netaddr.IPAddress('::1')),
(netaddr.IPAddress('::1'),
netaddr.IPAddress('::1'))]
self.coerce_bad_values = ['1-2', 'foo']
self.to_primitive_values = [(netaddr.IPAddress('1.2.3.4'), '1.2.3.4'),
(netaddr.IPAddress('::1'), '::1')]
self.from_primitive_values = [('1.2.3.4',
netaddr.IPAddress('1.2.3.4')),
('::1',
netaddr.IPAddress('::1'))]
class TestIPAddressV4(TestField):
def setUp(self):
super(TestIPAddressV4, self).setUp()
self.field = fields.IPV4AddressField()
self.coerce_good_values = [('1.2.3.4', netaddr.IPAddress('1.2.3.4')),
(netaddr.IPAddress('1.2.3.4'),
netaddr.IPAddress('1.2.3.4'))]
self.coerce_bad_values = ['1-2', 'foo', '::1']
self.to_primitive_values = [(netaddr.IPAddress('1.2.3.4'), '1.2.3.4')]
self.from_primitive_values = [('1.2.3.4',
netaddr.IPAddress('1.2.3.4'))]
class TestIPAddressV6(TestField):
def setUp(self):
super(TestIPAddressV6, self).setUp()
self.field = fields.IPV6AddressField()
self.coerce_good_values = [('::1', netaddr.IPAddress('::1')),
(netaddr.IPAddress('::1'),
netaddr.IPAddress('::1'))]
self.coerce_bad_values = ['1.2', 'foo', '1.2.3.4']
self.to_primitive_values = [(netaddr.IPAddress('::1'), '::1')]
self.from_primitive_values = [('::1',
netaddr.IPAddress('::1'))]
class TestDict(TestField):
def setUp(self):
super(TestDict, self).setUp()
@@ -332,7 +288,7 @@ class TestObject(TestField):
super(TestObject, self).setUp()
@obj_base.VersionedObjectRegistry.register
class TestableObject(obj_base.NovaObject):
class TestableObject(obj_base.VersionedObject):
fields = {
'uuid': fields.StringField(),
}
@@ -343,7 +299,7 @@ class TestObject(TestField):
# just want to make sure the right type of object is re-created
return value.__class__.__name__ == TestableObject.__name__
class OtherTestableObject(obj_base.NovaObject):
class OtherTestableObject(obj_base.VersionedObject):
pass
test_inst = TestableObject()
@@ -360,45 +316,3 @@ class TestObject(TestField):
obj = self._test_cls(uuid='fake-uuid')
self.assertEqual('TestableObject(fake-uuid)',
self.field.stringify(obj))
class TestIPNetwork(TestField):
def setUp(self):
super(TestIPNetwork, self).setUp()
self.field = fields.Field(fields.IPNetwork())
good = ['192.168.1.0/24', '0.0.0.0/0', '::1/128', '::1/64', '::1/0']
self.coerce_good_values = [(x, netaddr.IPNetwork(x)) for x in good]
self.coerce_bad_values = ['192.168.0.0/f', '192.168.0.0/foo',
'::1/129', '192.168.0.0/-1']
self.to_primitive_values = [(netaddr.IPNetwork(x), x)
for x in good]
self.from_primitive_values = [(x, netaddr.IPNetwork(x))
for x in good]
class TestIPV4Network(TestField):
def setUp(self):
super(TestIPV4Network, self).setUp()
self.field = fields.Field(fields.IPV4Network())
good = ['192.168.1.0/24', '0.0.0.0/0']
self.coerce_good_values = [(x, netaddr.IPNetwork(x)) for x in good]
self.coerce_bad_values = ['192.168.0.0/f', '192.168.0.0/foo',
'::1/129', '192.168.0.0/-1']
self.to_primitive_values = [(netaddr.IPNetwork(x), x)
for x in good]
self.from_primitive_values = [(x, netaddr.IPNetwork(x))
for x in good]
class TestIPV6Network(TestField):
def setUp(self):
super(TestIPV6Network, self).setUp()
self.field = fields.Field(fields.IPV6Network())
good = ['::1/128', '::1/64', '::1/0']
self.coerce_good_values = [(x, netaddr.IPNetwork(x)) for x in good]
self.coerce_bad_values = ['192.168.0.0/f', '192.168.0.0/foo',
'::1/129', '192.168.0.0/-1']
self.to_primitive_values = [(netaddr.IPNetwork(x), x)
for x in good]
self.from_primitive_values = [(x, netaddr.IPNetwork(x))
for x in good]

215
oslo_versionedobjects/tests/test_objects.py Normal file → Executable file
View File

@@ -27,13 +27,10 @@ from oslo_serialization import jsonutils
from oslo_utils import timeutils
from testtools import matchers
# from nova.conductor import rpcapi as conductor_rpcapi
from oslo_versionedobjects import base
from oslo_versionedobjects import exception
from oslo_versionedobjects import fields
# from nova import rpc
from oslo_versionedobjects import test
# from nova.tests.unit import fake_notifier
from oslo_versionedobjects import utils
@@ -49,14 +46,14 @@ def is_test_object(cls):
@base.VersionedObjectRegistry.register
class MyOwnedObject(base.NovaPersistentObject, base.NovaObject):
class MyOwnedObject(base.VersionedPersistentObject, base.VersionedObject):
VERSION = '1.0'
fields = {'baz': fields.Field(fields.Integer())}
@base.VersionedObjectRegistry.register
class MyObj(base.NovaPersistentObject, base.NovaObject,
base.NovaObjectDictCompat):
class MyObj(base.VersionedPersistentObject, base.VersionedObject,
base.VersionedObjectDictCompat):
VERSION = '1.6'
fields = {'foo': fields.Field(fields.Integer(), default=1),
'bar': fields.Field(fields.String()),
@@ -134,7 +131,7 @@ class MyObjDiffVers(MyObj):
@base.VersionedObjectRegistry.register
class MyObj2(base.NovaObject):
class MyObj2(base.VersionedObject):
@classmethod
def obj_name(cls):
return 'MyObj'
@@ -210,14 +207,14 @@ class TestRegistry(test.TestCase):
def test_field_checking(self):
def create_class(field):
@base.VersionedObjectRegistry.register
class TestField(base.NovaObject):
class TestField(base.VersionedObject):
VERSION = '1.5'
fields = {'foo': field()}
return TestField
create_class(fields.IPV4AndV6AddressField)
create_class(fields.DateTimeField)
self.assertRaises(exception.ObjectFieldInvalid,
create_class, fields.IPV4AndV6Address)
create_class, fields.DateTime)
self.assertRaises(exception.ObjectFieldInvalid,
create_class, int)
@@ -226,7 +223,7 @@ class TestObjToPrimitive(test.TestCase):
def test_obj_to_primitive_list(self):
@base.VersionedObjectRegistry.register
class MyObjElement(base.NovaObject):
class MyObjElement(base.VersionedObject):
fields = {'foo': fields.IntegerField()}
def __init__(self, foo):
@@ -234,7 +231,7 @@ class TestObjToPrimitive(test.TestCase):
self.foo = foo
@base.VersionedObjectRegistry.register
class MyList(base.ObjectListBase, base.NovaObject):
class MyList(base.ObjectListBase, base.VersionedObject):
fields = {'objects': fields.ListOfObjectsField('MyObjElement')}
mylist = MyList()
@@ -249,7 +246,7 @@ class TestObjToPrimitive(test.TestCase):
def test_obj_to_primitive_recursive(self):
@base.VersionedObjectRegistry.register
class MyList(base.ObjectListBase, base.NovaObject):
class MyList(base.ObjectListBase, base.VersionedObject):
fields = {'objects': fields.ListOfObjectsField('MyObj')}
mylist = MyList(objects=[MyObj(), MyObj()])
@@ -258,22 +255,12 @@ class TestObjToPrimitive(test.TestCase):
self.assertEqual([{'foo': 0}, {'foo': 1}],
base.obj_to_primitive(mylist))
def test_obj_to_primitive_with_ip_addr(self):
@base.VersionedObjectRegistry.register
class TestObject(base.NovaObject):
fields = {'addr': fields.IPAddressField(),
'cidr': fields.IPNetworkField()}
obj = TestObject(addr='1.2.3.4', cidr='1.1.1.1/16')
self.assertEqual({'addr': '1.2.3.4', 'cidr': '1.1.1.1/16'},
base.obj_to_primitive(obj))
class TestObjMakeList(test.TestCase):
def test_obj_make_list(self):
@base.VersionedObjectRegistry.register
class MyList(base.ObjectListBase, base.NovaObject):
class MyList(base.ObjectListBase, base.VersionedObject):
pass
db_objs = [{'foo': 1, 'bar': 'baz', 'missing': 'banana'},
@@ -290,13 +277,13 @@ class TestObjMakeList(test.TestCase):
def compare_obj(test, obj, db_obj, subs=None, allow_missing=None,
comparators=None):
"""Compare a NovaObject and a dict-like database object.
"""Compare a VersionedObject and a dict-like database object.
This automatically converts TZ-aware datetimes and iterates over
the fields of the object.
:param:test: The TestCase doing the comparison
:param:obj: The NovaObject to examine
:param:obj: The VersionedObject to examine
:param:db_obj: The dict-like database object to use as reference
:param:subs: A dict of objkey=dbkey field substitutions
:param:allow_missing: A list of fields that may not be in db_obj
@@ -370,7 +357,7 @@ class _LocalTest(_BaseTestCase):
def setUp(self):
super(_LocalTest, self).setUp()
# Just in case
base.NovaObject.indirection_api = None
base.VersionedObject.indirection_api = None
def assertRemotes(self):
self.assertEqual(self.remote_object_calls, [])
@@ -380,10 +367,10 @@ class _LocalTest(_BaseTestCase):
def things_temporarily_local():
# Temporarily go non-remote so the conductor handles
# this request directly
_api = base.NovaObject.indirection_api
base.NovaObject.indirection_api = None
_api = base.VersionedObject.indirection_api
base.VersionedObject.indirection_api = None
yield
base.NovaObject.indirection_api = _api
base.VersionedObject.indirection_api = _api
class _RemoteTest(_BaseTestCase):
@@ -402,8 +389,9 @@ class _RemoteTest(_BaseTestCase):
kwargs.get('objmethod')))
with things_temporarily_local():
result = orig_object_class_action(*args, **kwargs)
return (base.NovaObject.obj_from_primitive(result, context=args[0])
if isinstance(result, base.NovaObject) else result)
return (base.VersionedObject.obj_from_primitive(result,
context=args[0])
if isinstance(result, base.VersionedObject) else result)
self.stubs.Set(self.conductor_service.manager, 'object_class_action',
fake_object_class_action)
@@ -418,7 +406,7 @@ class _RemoteTest(_BaseTestCase):
# Things are remoted by default in this session
# FIXME(dhellmann): See work items in adopt-oslo-versionedobjects.
# base.NovaObject.indirection_api = conductor_rpcapi.ConductorAPI()
# base.VersionedObject.indirection_api =conductor_rpcapi.ConductorAPI()
# To make sure local and remote contexts match
# FIXME(dhellmann): See work items in adopt-oslo-versionedobjects.
@@ -449,17 +437,17 @@ class _TestObject(object):
# self.assertEqual('1.6', objects.MyObj.VERSION)
def test_hydration_type_error(self):
primitive = {'nova_object.name': 'MyObj',
'nova_object.namespace': 'nova',
'nova_object.version': '1.5',
'nova_object.data': {'foo': 'a'}}
primitive = {'versioned_object.name': 'MyObj',
'versioned_object.namespace': 'versionedobjects',
'versioned_object.version': '1.5',
'versioned_object.data': {'foo': 'a'}}
self.assertRaises(ValueError, MyObj.obj_from_primitive, primitive)
def test_hydration(self):
primitive = {'nova_object.name': 'MyObj',
'nova_object.namespace': 'nova',
'nova_object.version': '1.5',
'nova_object.data': {'foo': 1}}
primitive = {'versioned_object.name': 'MyObj',
'versioned_object.namespace': 'versionedobjects',
'versioned_object.version': '1.5',
'versioned_object.data': {'foo': 1}}
real_method = MyObj._obj_from_primitive
def _obj_from_primitive(*args):
@@ -472,27 +460,27 @@ class _TestObject(object):
self.assertEqual(obj.foo, 1)
def test_hydration_version_different(self):
primitive = {'nova_object.name': 'MyObj',
'nova_object.namespace': 'nova',
'nova_object.version': '1.2',
'nova_object.data': {'foo': 1}}
primitive = {'versioned_object.name': 'MyObj',
'versioned_object.namespace': 'versionedobjects',
'versioned_object.version': '1.2',
'versioned_object.data': {'foo': 1}}
obj = MyObj.obj_from_primitive(primitive)
self.assertEqual(obj.foo, 1)
self.assertEqual('1.2', obj.VERSION)
def test_hydration_bad_ns(self):
primitive = {'nova_object.name': 'MyObj',
'nova_object.namespace': 'foo',
'nova_object.version': '1.5',
'nova_object.data': {'foo': 1}}
primitive = {'versioned_object.name': 'MyObj',
'versioned_object.namespace': 'foo',
'versioned_object.version': '1.5',
'versioned_object.data': {'foo': 1}}
self.assertRaises(exception.UnsupportedObjectError,
MyObj.obj_from_primitive, primitive)
def test_hydration_additional_unexpected_stuff(self):
primitive = {'nova_object.name': 'MyObj',
'nova_object.namespace': 'nova',
'nova_object.version': '1.5.1',
'nova_object.data': {
primitive = {'versioned_object.name': 'MyObj',
'versioned_object.namespace': 'versionedobjects',
'versioned_object.version': '1.5.1',
'versioned_object.data': {
'foo': 1,
'unexpected_thing': 'foobar'}}
obj = MyObj.obj_from_primitive(primitive)
@@ -506,10 +494,10 @@ class _TestObject(object):
self.assertEqual('1.5.1', obj.VERSION)
def test_dehydration(self):
expected = {'nova_object.name': 'MyObj',
'nova_object.namespace': 'nova',
'nova_object.version': '1.6',
'nova_object.data': {'foo': 1}}
expected = {'versioned_object.name': 'MyObj',
'versioned_object.namespace': 'versionedobjects',
'versioned_object.version': '1.6',
'versioned_object.data': {'foo': 1}}
obj = MyObj(foo=1)
obj.obj_reset_changes()
self.assertEqual(obj.obj_to_primitive(), expected)
@@ -539,7 +527,7 @@ class _TestObject(object):
def test_load_in_base(self):
@base.VersionedObjectRegistry.register
class Foo(base.NovaObject):
class Foo(base.VersionedObject):
fields = {'foobar': fields.Field(fields.Integer())}
obj = Foo()
with self.assertRaisesRegex(NotImplementedError, ".*foobar.*"):
@@ -549,40 +537,41 @@ class _TestObject(object):
obj = MyObj(foo=1)
obj.obj_reset_changes()
self.assertEqual(obj.bar, 'loaded!')
expected = {'nova_object.name': 'MyObj',
'nova_object.namespace': 'nova',
'nova_object.version': '1.6',
'nova_object.changes': ['bar'],
'nova_object.data': {'foo': 1,
'bar': 'loaded!'}}
expected = {'versioned_object.name': 'MyObj',
'versioned_object.namespace': 'versionedobjects',
'versioned_object.version': '1.6',
'versioned_object.changes': ['bar'],
'versioned_object.data': {'foo': 1,
'bar': 'loaded!'}}
self.assertEqual(obj.obj_to_primitive(), expected)
def test_changes_in_primitive(self):
obj = MyObj(foo=123)
self.assertEqual(obj.obj_what_changed(), set(['foo']))
primitive = obj.obj_to_primitive()
self.assertIn('nova_object.changes', primitive)
self.assertIn('versioned_object.changes', primitive)
obj2 = MyObj.obj_from_primitive(primitive)
self.assertEqual(obj2.obj_what_changed(), set(['foo']))
obj2.obj_reset_changes()
self.assertEqual(obj2.obj_what_changed(), set())
def test_obj_class_from_name(self):
obj = base.NovaObject.obj_class_from_name('MyObj', '1.5')
obj = base.VersionedObject.obj_class_from_name('MyObj', '1.5')
self.assertEqual('1.5', obj.VERSION)
def test_obj_class_from_name_latest_compatible(self):
obj = base.NovaObject.obj_class_from_name('MyObj', '1.1')
obj = base.VersionedObject.obj_class_from_name('MyObj', '1.1')
self.assertEqual('1.6', obj.VERSION)
def test_unknown_objtype(self):
self.assertRaises(exception.UnsupportedObjectError,
base.NovaObject.obj_class_from_name, 'foo', '1.0')
base.VersionedObject.obj_class_from_name,
'foo', '1.0')
def test_obj_class_from_name_supported_version(self):
error = None
try:
base.NovaObject.obj_class_from_name('MyObj', '1.25')
base.VersionedObject.obj_class_from_name('MyObj', '1.25')
except exception.IncompatibleObjectVersion as error:
pass
@@ -637,7 +626,7 @@ class _TestObject(object):
def test_changed_with_sub_object(self):
@base.VersionedObjectRegistry.register
class ParentObject(base.NovaObject):
class ParentObject(base.VersionedObject):
fields = {'foo': fields.IntegerField(),
'bar': fields.ObjectField('MyObj'),
}
@@ -672,13 +661,13 @@ class _TestObject(object):
obj = MyObj(created_at=dt, updated_at=dt, deleted_at=None,
deleted=False)
expected = {
'nova_object.name': 'MyObj',
'nova_object.namespace': 'nova',
'nova_object.version': '1.6',
'nova_object.changes': [
'versioned_object.name': 'MyObj',
'versioned_object.namespace': 'versionedobjects',
'versioned_object.version': '1.6',
'versioned_object.changes': [
'deleted', 'created_at', 'deleted_at', 'updated_at',
],
'nova_object.data': {
'versioned_object.data': {
'created_at': timeutils.isotime(dt),
'updated_at': timeutils.isotime(dt),
'deleted_at': None,
@@ -718,7 +707,7 @@ class _TestObject(object):
self.assertRaises(AttributeError, obj.get, 'nothing', 3)
def test_object_inheritance(self):
base_fields = base.NovaPersistentObject.fields.keys()
base_fields = base.VersionedPersistentObject.fields.keys()
myobj_fields = (['foo', 'bar', 'missing',
'readonly', 'rel_object', 'rel_objects'] +
base_fields)
@@ -764,7 +753,7 @@ class _TestObject(object):
self.assertEqual({}, obj.obj_get_changes())
def test_obj_fields(self):
class TestObj(base.NovaObject):
class TestObj(base.VersionedObject):
fields = {'foo': fields.Field(fields.Integer())}
obj_extra_fields = ['bar']
@@ -800,7 +789,7 @@ class _TestObject(object):
obj.obj_relationships = {
'rel_object': [('1.5', '1.1'), ('1.7', '1.2')],
}
primitive = obj.obj_to_primitive()['nova_object.data']
primitive = obj.obj_to_primitive()['versioned_object.data']
with mock.patch.object(subobj, 'obj_make_compatible') as mock_compat:
obj._obj_make_obj_compatible(copy.copy(primitive), '1.8',
'rel_object')
@@ -810,25 +799,25 @@ class _TestObject(object):
obj._obj_make_obj_compatible(copy.copy(primitive),
'1.7', 'rel_object')
mock_compat.assert_called_once_with(
primitive['rel_object']['nova_object.data'], '1.2')
self.assertEqual('1.2',
primitive['rel_object']['nova_object.version'])
primitive['rel_object']['versioned_object.data'], '1.2')
self.assertEqual(
'1.2', primitive['rel_object']['versioned_object.version'])
with mock.patch.object(subobj, 'obj_make_compatible') as mock_compat:
obj._obj_make_obj_compatible(copy.copy(primitive),
'1.6', 'rel_object')
mock_compat.assert_called_once_with(
primitive['rel_object']['nova_object.data'], '1.1')
self.assertEqual('1.1',
primitive['rel_object']['nova_object.version'])
primitive['rel_object']['versioned_object.data'], '1.1')
self.assertEqual(
'1.1', primitive['rel_object']['versioned_object.version'])
with mock.patch.object(subobj, 'obj_make_compatible') as mock_compat:
obj._obj_make_obj_compatible(copy.copy(primitive), '1.5',
'rel_object')
mock_compat.assert_called_once_with(
primitive['rel_object']['nova_object.data'], '1.1')
self.assertEqual('1.1',
primitive['rel_object']['nova_object.version'])
primitive['rel_object']['versioned_object.data'], '1.1')
self.assertEqual(
'1.1', primitive['rel_object']['versioned_object.version'])
with mock.patch.object(subobj, 'obj_make_compatible') as mock_compat:
_prim = copy.copy(primitive)
@@ -924,14 +913,14 @@ class TestRemoteObject(_RemoteTest, _TestObject):
class TestObjectListBase(test.TestCase):
def test_list_like_operations(self):
@base.VersionedObjectRegistry.register
class MyElement(base.NovaObject):
class MyElement(base.VersionedObject):
fields = {'foo': fields.IntegerField()}
def __init__(self, foo):
super(MyElement, self).__init__()
self.foo = foo
class Foo(base.ObjectListBase, base.NovaObject):
class Foo(base.ObjectListBase, base.VersionedObject):
fields = {'objects': fields.ListOfObjectsField('MyElement')}
objlist = Foo(context='foo',
@@ -950,11 +939,11 @@ class TestObjectListBase(test.TestCase):
def test_serialization(self):
@base.VersionedObjectRegistry.register
class Foo(base.ObjectListBase, base.NovaObject):
class Foo(base.ObjectListBase, base.VersionedObject):
fields = {'objects': fields.ListOfObjectsField('Bar')}
@base.VersionedObjectRegistry.register
class Bar(base.NovaObject):
class Bar(base.VersionedObject):
fields = {'foo': fields.Field(fields.String())}
obj = Foo(objects=[])
@@ -962,7 +951,7 @@ class TestObjectListBase(test.TestCase):
bar = Bar(foo=i)
obj.objects.append(bar)
obj2 = base.NovaObject.obj_from_primitive(obj.obj_to_primitive())
obj2 = base.VersionedObject.obj_from_primitive(obj.obj_to_primitive())
self.assertFalse(obj is obj2)
self.assertEqual([x.foo for x in obj],
[y.foo for y in obj2])
@@ -995,11 +984,11 @@ class TestObjectListBase(test.TestCase):
def test_list_changes(self):
@base.VersionedObjectRegistry.register
class Foo(base.ObjectListBase, base.NovaObject):
class Foo(base.ObjectListBase, base.VersionedObject):
fields = {'objects': fields.ListOfObjectsField('Bar')}
@base.VersionedObjectRegistry.register
class Bar(base.NovaObject):
class Bar(base.VersionedObject):
fields = {'foo': fields.StringField()}
obj = Foo(objects=[])
@@ -1014,10 +1003,10 @@ class TestObjectListBase(test.TestCase):
self.assertEqual(set(), obj.obj_what_changed())
def test_initialize_objects(self):
class Foo(base.ObjectListBase, base.NovaObject):
class Foo(base.ObjectListBase, base.VersionedObject):
fields = {'objects': fields.ListOfObjectsField('Bar')}
class Bar(base.NovaObject):
class Bar(base.VersionedObject):
fields = {'foo': fields.StringField()}
obj = Foo()
@@ -1026,11 +1015,11 @@ class TestObjectListBase(test.TestCase):
def test_obj_repr(self):
@base.VersionedObjectRegistry.register
class Foo(base.ObjectListBase, base.NovaObject):
class Foo(base.ObjectListBase, base.VersionedObject):
fields = {'objects': fields.ListOfObjectsField('Bar')}
@base.VersionedObjectRegistry.register
class Bar(base.NovaObject):
class Bar(base.VersionedObject):
fields = {'uuid': fields.StringField()}
obj = Foo(objects=[Bar(uuid='fake-uuid')])
@@ -1039,22 +1028,22 @@ class TestObjectListBase(test.TestCase):
class TestObjectSerializer(_BaseTestCase):
def test_serialize_entity_primitive(self):
ser = base.NovaObjectSerializer()
ser = base.VersionedObjectSerializer()
for thing in (1, 'foo', [1, 2], {'foo': 'bar'}):
self.assertEqual(thing, ser.serialize_entity(None, thing))
def test_deserialize_entity_primitive(self):
ser = base.NovaObjectSerializer()
ser = base.VersionedObjectSerializer()
for thing in (1, 'foo', [1, 2], {'foo': 'bar'}):
self.assertEqual(thing, ser.deserialize_entity(None, thing))
def test_serialize_set_to_list(self):
ser = base.NovaObjectSerializer()
ser = base.VersionedObjectSerializer()
self.assertEqual([1, 2], ser.serialize_entity(None, set([1, 2])))
def _test_deserialize_entity_newer(self, obj_version, backported_to,
my_version='1.6'):
ser = base.NovaObjectSerializer()
ser = base.VersionedObjectSerializer()
ser._conductor = mock.Mock()
ser._conductor.object_backport.return_value = 'backported'
@@ -1087,13 +1076,13 @@ class TestObjectSerializer(_BaseTestCase):
self._test_deserialize_entity_newer('1.7', '1.6.1', '1.6.1')
def test_deserialize_dot_z_with_extra_stuff(self):
primitive = {'nova_object.name': 'MyObj',
'nova_object.namespace': 'nova',
'nova_object.version': '1.6.1',
'nova_object.data': {
primitive = {'versioned_object.name': 'MyObj',
'versioned_object.namespace': 'versionedobjects',
'versioned_object.version': '1.6.1',
'versioned_object.data': {
'foo': 1,
'unexpected_thing': 'foobar'}}
ser = base.NovaObjectSerializer()
ser = base.VersionedObjectSerializer()
obj = ser.deserialize_entity(self.context, primitive)
self.assertEqual(1, obj.foo)
self.assertFalse(hasattr(obj, 'unexpected_thing'))
@@ -1105,23 +1094,23 @@ class TestObjectSerializer(_BaseTestCase):
self.assertEqual('1.6', obj.VERSION)
def test_object_serialization(self):
ser = base.NovaObjectSerializer()
ser = base.VersionedObjectSerializer()
obj = MyObj()
primitive = ser.serialize_entity(self.context, obj)
self.assertIn('nova_object.name', primitive)
self.assertIn('versioned_object.name', primitive)
obj2 = ser.deserialize_entity(self.context, primitive)
self.assertIsInstance(obj2, MyObj)
self.assertEqual(self.context, obj2._context)
def test_object_serialization_iterables(self):
ser = base.NovaObjectSerializer()
ser = base.VersionedObjectSerializer()
obj = MyObj()
for iterable in (list, tuple, set):
thing = iterable([obj])
primitive = ser.serialize_entity(self.context, thing)
self.assertEqual(1, len(primitive))
for item in primitive:
self.assertNotIsInstance(item, base.NovaObject)
self.assertNotIsInstance(item, base.VersionedObject)
thing2 = ser.deserialize_entity(self.context, primitive)
self.assertEqual(1, len(thing2))
for item in thing2:
@@ -1131,7 +1120,7 @@ class TestObjectSerializer(_BaseTestCase):
primitive = ser.serialize_entity(self.context, thing)
self.assertEqual(1, len(primitive))
for item in primitive.itervalues():
self.assertNotIsInstance(item, base.NovaObject)
self.assertNotIsInstance(item, base.VersionedObject)
thing2 = ser.deserialize_entity(self.context, primitive)
self.assertEqual(1, len(thing2))
for item in thing2.itervalues():
@@ -1142,7 +1131,7 @@ class TestObjectSerializer(_BaseTestCase):
primitive = ser.serialize_entity(self.context, thing)
self.assertEqual(thing, primitive)
thing2 = ser.deserialize_entity(self.context, thing)
self.assertIsInstance(thing2['foo'], base.NovaObject)
self.assertIsInstance(thing2['foo'], base.VersionedObject)
# NOTE(danms): The hashes in this list should only be changed if

2
oslo_versionedobjects/tests/test_utils.py Normal file → Executable file
View File

@@ -26,7 +26,7 @@ class VersionTestCase(test.NoDBTestCase):
self.assertEqual(utils.convert_version_to_int('6.2.0'), 6002000)
self.assertEqual(utils.convert_version_to_int((6, 4, 3)), 6004003)
self.assertEqual(utils.convert_version_to_int((5, )), 5)
self.assertRaises(exception.NovaException,
self.assertRaises(exception.VersionedObjectsException,
utils.convert_version_to_int, '5a.6b')
def test_convert_version_to_string(self):

View File

@@ -35,7 +35,7 @@ def convert_version_to_int(version):
return reduce(lambda x, y: (x * 1000) + y, version)
except Exception:
msg = _("Hypervisor version %s is invalid.") % version
raise exception.NovaException(msg)
raise exception.VersionedObjectsException(msg)
def convert_version_to_str(version_int):