summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--nova/api/ec2/cloud.py3
-rwxr-xr-xnova/compute/manager.py3
-rw-r--r--nova/objects/base.py26
-rw-r--r--nova/objects/instance.py12
-rw-r--r--nova/objects/instance_info_cache.py5
-rw-r--r--nova/tests/objects/test_objects.py37
6 files changed, 74 insertions, 12 deletions
diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py
index e02f7b6f9..51a86e02f 100644
--- a/nova/api/ec2/cloud.py
+++ b/nova/api/ec2/cloud.py
@@ -211,9 +211,8 @@ def db_to_inst_obj(context, db_instance):
# NOTE(danms): This is a temporary helper method for converting
# Instance DB objects to NovaObjects without needing to re-query.
inst_obj = instance_obj.Instance._from_db_object(
- instance_obj.Instance(), db_instance,
+ context, instance_obj.Instance(), db_instance,
expected_attrs=['system_metadata', 'metadata'])
- inst_obj._context = context
return inst_obj
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index 1a6479f7f..22881f5bd 100755
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -282,7 +282,8 @@ def object_compat(function):
instance = kwargs['instance']
if isinstance(instance, dict):
kwargs['instance'] = instance_obj.Instance._from_db_object(
- instance_obj.Instance(), instance, expected_attrs=metas)
+ context, instance_obj.Instance(), instance,
+ expected_attrs=metas)
kwargs['instance']._context = context
return function(self, context, **kwargs)
diff --git a/nova/objects/base.py b/nova/objects/base.py
index f5fc37e03..6f2b6c81f 100644
--- a/nova/objects/base.py
+++ b/nova/objects/base.py
@@ -425,13 +425,35 @@ class NovaObjectSerializer(nova.openstack.common.rpc.serializer.Serializer):
that needs to accept or return NovaObjects as arguments or result values
should pass this to its RpcProxy and RpcDispatcher objects.
"""
+ def _process_iterable(self, context, action_fn, values):
+ """Process an iterable, taking an action on each value.
+ :param:context: Request context
+ :param:action_fn: Action to take on each item in values
+ :param:values: Iterable container of things to take action on
+ :returns: A new container of the same type (except set) with
+ items from values having had action applied.
+ """
+ iterable = values.__class__
+ if iterable == set:
+ # NOTE(danms): A set can't have an unhashable value inside, such as
+ # a dict. Convert sets to tuples, which is fine, since we can't
+ # send them over RPC anyway.
+ iterable = tuple
+ return iterable([action_fn(context, value) for value in values])
+
def serialize_entity(self, context, entity):
- if (hasattr(entity, 'obj_to_primitive') and
- callable(entity.obj_to_primitive)):
+ if isinstance(entity, (tuple, list, set)):
+ entity = self._process_iterable(context, self.serialize_entity,
+ entity)
+ elif (hasattr(entity, 'obj_to_primitive') and
+ callable(entity.obj_to_primitive)):
entity = entity.obj_to_primitive()
return entity
def deserialize_entity(self, context, entity):
if isinstance(entity, dict) and 'nova_object.name' in entity:
entity = NovaObject.obj_from_primitive(entity, context=context)
+ elif isinstance(entity, (tuple, list, set)):
+ entity = self._process_iterable(context, self.deserialize_entity,
+ entity)
return entity
diff --git a/nova/objects/instance.py b/nova/objects/instance.py
index de47f648f..55e98e46e 100644
--- a/nova/objects/instance.py
+++ b/nova/objects/instance.py
@@ -158,7 +158,7 @@ class Instance(base.NovaObject):
return base.NovaObject.obj_from_primitive(val)
@staticmethod
- def _from_db_object(instance, db_inst, expected_attrs=None):
+ def _from_db_object(context, instance, db_inst, expected_attrs=None):
"""Method to help with migration to objects.
Converts a database entity to a formal object.
@@ -185,8 +185,9 @@ class Instance(base.NovaObject):
if db_inst['info_cache']:
instance['info_cache'] = instance_info_cache.InstanceInfoCache()
instance_info_cache.InstanceInfoCache._from_db_object(
- instance['info_cache'], db_inst['info_cache'])
+ context, instance['info_cache'], db_inst['info_cache'])
+ instance._context = context
instance.obj_reset_changes()
return instance
@@ -207,7 +208,8 @@ class Instance(base.NovaObject):
db_inst = db.instance_get_by_uuid(context, uuid,
columns_to_join)
- return Instance._from_db_object(cls(), db_inst, expected_attrs)
+ return Instance._from_db_object(context, cls(), db_inst,
+ expected_attrs)
@base.remotable
def save(self, context, expected_task_state=None):
@@ -240,7 +242,7 @@ class Instance(base.NovaObject):
for attr in INSTANCE_OPTIONAL_FIELDS:
if hasattr(self, base.get_attrname(attr)):
expected_attrs.append(attr)
- Instance._from_db_object(self, inst_ref, expected_attrs)
+ Instance._from_db_object(context, self, inst_ref, expected_attrs)
if 'vm_state' in changes or 'task_state' in changes:
notifications.send_update(context, old_ref, inst_ref)
@@ -282,7 +284,7 @@ class Instance(base.NovaObject):
def _make_instance_list(context, inst_list, db_inst_list, expected_attrs):
inst_list.objects = []
for db_inst in db_inst_list:
- inst_obj = Instance._from_db_object(Instance(), db_inst,
+ inst_obj = Instance._from_db_object(context, Instance(), db_inst,
expected_attrs=expected_attrs)
inst_obj._context = context
inst_list.objects.append(inst_obj)
diff --git a/nova/objects/instance_info_cache.py b/nova/objects/instance_info_cache.py
index 6b46559ed..a14175852 100644
--- a/nova/objects/instance_info_cache.py
+++ b/nova/objects/instance_info_cache.py
@@ -23,16 +23,17 @@ class InstanceInfoCache(base.NovaObject):
}
@staticmethod
- def _from_db_object(info_cache, db_obj):
+ def _from_db_object(context, info_cache, db_obj):
info_cache.instance_uuid = db_obj['instance_uuid']
info_cache.network_info = db_obj['network_info']
info_cache.obj_reset_changes()
+ info_cache._context = context
return info_cache
@base.remotable_classmethod
def get_by_instance_uuid(cls, context, instance_uuid):
db_obj = db.instance_info_cache_get(context, instance_uuid)
- return InstanceInfoCache._from_db_object(cls(), db_obj)
+ return InstanceInfoCache._from_db_object(context, cls(), db_obj)
@base.remotable
def save(self, context):
diff --git a/nova/tests/objects/test_objects.py b/nova/tests/objects/test_objects.py
index 332833cb0..00aaf1781 100644
--- a/nova/tests/objects/test_objects.py
+++ b/nova/tests/objects/test_objects.py
@@ -502,3 +502,40 @@ class TestObjectListBase(test.TestCase):
self.assertFalse(obj is obj2)
self.assertEqual([x.foo for x in obj],
[y.foo for y in obj2])
+
+
+class TestObjectSerializer(test.TestCase):
+ def test_serialize_entity_primitive(self):
+ ser = base.NovaObjectSerializer()
+ 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()
+ for thing in (1, 'foo', [1, 2], {'foo': 'bar'}):
+ self.assertEqual(thing, ser.deserialize_entity(None, thing))
+
+ def test_object_serialization(self):
+ ser = base.NovaObjectSerializer()
+ ctxt = context.get_admin_context()
+ obj = MyObj()
+ primitive = ser.serialize_entity(ctxt, obj)
+ self.assertTrue('nova_object.name' in primitive)
+ obj2 = ser.deserialize_entity(ctxt, primitive)
+ self.assertTrue(isinstance(obj2, MyObj))
+ self.assertEqual(ctxt, obj2._context)
+
+ def test_object_serialization_iterables(self):
+ ser = base.NovaObjectSerializer()
+ ctxt = context.get_admin_context()
+ obj = MyObj()
+ for iterable in (list, tuple, set):
+ thing = iterable([obj])
+ primitive = ser.serialize_entity(ctxt, thing)
+ self.assertEqual(1, len(primitive))
+ for item in primitive:
+ self.assertFalse(isinstance(item, base.NovaObject))
+ thing2 = ser.deserialize_entity(ctxt, primitive)
+ self.assertEqual(1, len(thing2))
+ for item in thing2:
+ self.assertTrue(isinstance(item, MyObj))