Merge "Support nested objects and object lists in as_dict"
This commit is contained in:
commit
a935a3ec56
@ -1051,7 +1051,7 @@ class Node(base.APIBase):
|
||||
self.fields.append(k)
|
||||
# TODO(jroll) is there a less hacky way to do this?
|
||||
if k == 'traits' and kwargs.get('traits') is not None:
|
||||
value = kwargs['traits'].get_trait_names()
|
||||
value = [t['trait'] for t in kwargs['traits']['objects']]
|
||||
else:
|
||||
value = kwargs.get(k, wtypes.Unset)
|
||||
setattr(self, k, value)
|
||||
|
@ -64,9 +64,21 @@ class IronicObject(object_base.VersionedObject):
|
||||
}
|
||||
|
||||
def as_dict(self):
|
||||
return dict((k, getattr(self, k))
|
||||
"""Return the object represented as a dict.
|
||||
|
||||
The returned object is JSON-serialisable.
|
||||
"""
|
||||
|
||||
def _attr_as_dict(field):
|
||||
"""Return an attribute as a dict, handling nested objects."""
|
||||
attr = getattr(self, field)
|
||||
if isinstance(attr, IronicObject):
|
||||
attr = attr.as_dict()
|
||||
return attr
|
||||
|
||||
return dict((k, _attr_as_dict(k))
|
||||
for k in self.fields
|
||||
if hasattr(self, k))
|
||||
if self.obj_attr_is_set(k))
|
||||
|
||||
def obj_refresh(self, loaded_object):
|
||||
"""Applies updates for objects that inherit from base.IronicObject.
|
||||
@ -320,6 +332,16 @@ class IronicObject(object_base.VersionedObject):
|
||||
return changes
|
||||
|
||||
|
||||
class IronicObjectListBase(object_base.ObjectListBase):
|
||||
|
||||
def as_dict(self):
|
||||
"""Return the object represented as a dict.
|
||||
|
||||
The returned object is JSON-serialisable.
|
||||
"""
|
||||
return {'objects': [obj.as_dict() for obj in self.objects]}
|
||||
|
||||
|
||||
class IronicObjectSerializer(object_base.VersionedObjectSerializer):
|
||||
# Base class to use for object hydration
|
||||
OBJ_BASE_CLASS = IronicObject
|
||||
|
@ -98,7 +98,7 @@ class Trait(base.IronicObject):
|
||||
|
||||
|
||||
@base.IronicObjectRegistry.register
|
||||
class TraitList(object_base.ObjectListBase, base.IronicObject):
|
||||
class TraitList(base.IronicObjectListBase, base.IronicObject):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
import datetime
|
||||
|
||||
import mock
|
||||
from oslo_serialization import jsonutils
|
||||
from oslo_utils import uuidutils
|
||||
from testtools import matchers
|
||||
|
||||
@ -41,6 +42,8 @@ class TestNodeObject(db_base.DbTestCase, obj_utils.SchemasTestMixIn):
|
||||
d = self.node.as_dict()
|
||||
self.assertEqual('fake', d['driver_info']['ipmi_password'])
|
||||
self.assertEqual('data', d['instance_info']['configdrive'])
|
||||
# Ensure the node can be serialised.
|
||||
jsonutils.dumps(d)
|
||||
|
||||
def test_as_dict_secure(self):
|
||||
self.node.driver_info['ipmi_password'] = 'fake'
|
||||
@ -48,6 +51,17 @@ class TestNodeObject(db_base.DbTestCase, obj_utils.SchemasTestMixIn):
|
||||
d = self.node.as_dict(secure=True)
|
||||
self.assertEqual('******', d['driver_info']['ipmi_password'])
|
||||
self.assertEqual('******', d['instance_info']['configdrive'])
|
||||
# Ensure the node can be serialised.
|
||||
jsonutils.dumps(d)
|
||||
|
||||
def test_as_dict_with_traits(self):
|
||||
self.fake_node['traits'] = ['CUSTOM_1']
|
||||
self.node = obj_utils.get_test_node(self.ctxt, **self.fake_node)
|
||||
d = self.node.as_dict()
|
||||
expected_traits = {'objects': [{'trait': 'CUSTOM_1'}]}
|
||||
self.assertEqual(expected_traits, d['traits'])
|
||||
# Ensure the node can be serialised.
|
||||
jsonutils.dumps(d)
|
||||
|
||||
def test_get_by_id(self):
|
||||
node_id = self.fake_node['id']
|
||||
|
@ -620,6 +620,40 @@ class _TestObject(object):
|
||||
self.assertIn("'TestObj' object does not support item assignment",
|
||||
err_message)
|
||||
|
||||
def test_as_dict(self):
|
||||
obj = MyObj(self.context)
|
||||
obj.foo = 1
|
||||
result = obj.as_dict()
|
||||
expected = {'foo': 1}
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
def test_as_dict_with_nested_object(self):
|
||||
@base.IronicObjectRegistry.register_if(False)
|
||||
class TestObj(base.IronicObject,
|
||||
object_base.VersionedObjectDictCompat):
|
||||
fields = {'my_obj': fields.ObjectField('MyObj')}
|
||||
|
||||
obj1 = MyObj(self.context)
|
||||
obj1.foo = 1
|
||||
obj2 = TestObj(self.context)
|
||||
obj2.my_obj = obj1
|
||||
result = obj2.as_dict()
|
||||
expected = {'my_obj': {'foo': 1}}
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
def test_as_dict_with_nested_object_list(self):
|
||||
@base.IronicObjectRegistry.register_if(False)
|
||||
class TestObj(base.IronicObjectListBase, base.IronicObject):
|
||||
fields = {'objects': fields.ListOfObjectsField('MyObj')}
|
||||
|
||||
obj1 = MyObj(self.context)
|
||||
obj1.foo = 1
|
||||
obj2 = TestObj(self.context)
|
||||
obj2.objects = [obj1]
|
||||
result = obj2.as_dict()
|
||||
expected = {'objects': [{'foo': 1}]}
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
|
||||
class TestObject(_LocalTest, _TestObject):
|
||||
pass
|
||||
|
@ -101,3 +101,15 @@ class TestTraitObject(db_base.DbTestCase, obj_utils.SchemasTestMixIn):
|
||||
result = trait_list.get_trait_names()
|
||||
|
||||
self.assertEqual([self.fake_trait['trait']], result)
|
||||
|
||||
def test_as_dict(self):
|
||||
trait = objects.Trait(context=self.context,
|
||||
node_id=self.fake_trait['node_id'],
|
||||
trait=self.fake_trait['trait'])
|
||||
trait_list = objects.TraitList(context=self.context, objects=[trait])
|
||||
|
||||
result = trait_list.as_dict()
|
||||
|
||||
expected = {'objects': [{'node_id': self.fake_trait['node_id'],
|
||||
'trait': self.fake_trait['trait']}]}
|
||||
self.assertEqual(expected, result)
|
||||
|
@ -0,0 +1,7 @@
|
||||
---
|
||||
fixes:
|
||||
- |
|
||||
Fixes an issue seen during cleaning when the node being cleaned has one or
|
||||
more traits assigned. This issue caused cleaning to fail, and the node to
|
||||
enter the ``clean failed`` state. See `bug 1750027
|
||||
<https://bugs.launchpad.net/ironic/+bug/1750027>`_ for details.
|
Loading…
x
Reference in New Issue
Block a user