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:
@@ -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."""
|
||||
|
||||
@@ -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]))
|
||||
|
||||
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user