Break out the meat of the object hydration process

Since we call the NovaObject base class to hydrate an object, the
subclass implementation does not get a chance to run specific code
during or after hydration. Things like Instance that keep local data for
change tracking need a chance to update themselves after hydration
is complete. This breaks out the meat into a separate method which
can be easily overridden in a subclass.

This also makes Instance use this to ensure metadata tracking is
up-to-date after hydration.

Related to blueprint compute-manager-objects

Change-Id: Ie070c17495f7a4cc6210d256a3170ac9c06e198f
This commit is contained in:
Dan Smith
2014-01-30 12:56:29 -08:00
parent 0bcf22e71d
commit 8218a86ded
3 changed files with 31 additions and 12 deletions

View File

@@ -223,6 +223,20 @@ class NovaObject(object):
objver=objver,
supported=latest_ver)
@classmethod
def _obj_from_primitive(cls, context, objver, primitive):
self = cls()
self._context = context
self.VERSION = objver
objdata = primitive['nova_object.data']
changes = primitive.get('nova_object.changes', [])
for name, field in self.fields.items():
if name in objdata:
setattr(self, name, field.from_primitive(self, name,
objdata[name]))
self._changed_fields = set([x for x in changes if x in self.fields])
return self
@classmethod
def obj_from_primitive(cls, primitive, context=None):
"""Object field-by-field hydration."""
@@ -234,18 +248,8 @@ class NovaObject(object):
primitive['nova_object.name']))
objname = primitive['nova_object.name']
objver = primitive['nova_object.version']
objdata = primitive['nova_object.data']
objclass = cls.obj_class_from_name(objname, objver)
self = objclass()
self._context = context
self.VERSION = objver
for name, field in self.fields.items():
if name in objdata:
setattr(self, name, field.from_primitive(self, name,
objdata[name]))
changes = primitive.get('nova_object.changes', [])
self._changed_fields = set([x for x in changes if x in self.fields])
return self
return objclass._obj_from_primitive(context, objver, primitive)
def __deepcopy__(self, memo):
"""Efficiently make a deep copy of this object."""

View File

@@ -188,6 +188,13 @@ class Instance(base.NovaPersistentObject, base.NovaObject):
changes.add('system_metadata')
return changes
@classmethod
def _obj_from_primitive(cls, context, objver, primitive):
self = super(Instance, cls)._obj_from_primitive(context, objver,
primitive)
self._reset_metadata_tracking()
return self
def obj_make_compatible(self, primitive, target_version):
target_version = (int(target_version.split('.')[0]),
int(target_version.split('.')[1]))

View File

@@ -426,7 +426,15 @@ class _TestObject(object):
'nova_object.namespace': 'nova',
'nova_object.version': '1.5',
'nova_object.data': {'foo': 1}}
obj = MyObj.obj_from_primitive(primitive)
real_method = MyObj._obj_from_primitive
def _obj_from_primitive(*args):
return real_method(*args)
with mock.patch.object(MyObj, '_obj_from_primitive') as ofp:
ofp.side_effect = _obj_from_primitive
obj = MyObj.obj_from_primitive(primitive)
ofp.assert_called_once_with(None, '1.5', primitive)
self.assertEqual(obj.foo, 1)
def test_hydration_version_different(self):