From 83cdec4123dba74ace3439204df9a76d0053ebe7 Mon Sep 17 00:00:00 2001 From: Hans Lindgren Date: Wed, 15 Apr 2015 11:42:32 +0200 Subject: [PATCH] Make objects serialize_args() handle datetimes in positional args Remotable methods in a new TaskLog object need to serialize datatimes passed as positional args. Right now the serialize_args() decorator only look at kwargs. In addition, serialization of datetimes need to use timeutils.strtime() to match the deserialization code in the db api. Also makes this change for serialization of kwargs to partially solve a bug with how this decorator is used in the BandwidthUsage object. A follow-up patch closes the bug by adding conversion back to datetimes using existing db api helper method convert_objects_related_datetimes(), which in turn makes use of timeutils.parse_strtime(). Related to blueprint liberty-objects Change-Id: Ia87be4fd37bee499510ae543e11029c2013d4905 Related-Bug: #1442795 --- nova/objects/base.py | 18 +++++++++--------- nova/tests/unit/objects/test_objects.py | 22 ++++++++++++++++++++++ 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/nova/objects/base.py b/nova/objects/base.py index 6837066cbddd..ce4df5b512f8 100644 --- a/nova/objects/base.py +++ b/nova/objects/base.py @@ -938,15 +938,15 @@ def obj_make_list(context, list_obj, item_cls, db_list, **extra_args): def serialize_args(fn): """Decorator that will do the arguments serialization before remoting.""" def wrapper(obj, *args, **kwargs): - for kw in kwargs: - value_arg = kwargs.get(kw) - if kw == 'exc_val' and value_arg: - kwargs[kw] = str(value_arg) - elif kw == 'exc_tb' and ( - not isinstance(value_arg, six.string_types) and value_arg): - kwargs[kw] = ''.join(traceback.format_tb(value_arg)) - elif isinstance(value_arg, datetime.datetime): - kwargs[kw] = timeutils.isotime(value_arg) + args = [timeutils.strtime(at=arg) if isinstance(arg, datetime.datetime) + else arg for arg in args] + for k, v in kwargs.iteritems(): + if k == 'exc_val' and v: + kwargs[k] = str(v) + elif k == 'exc_tb' and v and not isinstance(v, six.string_types): + kwargs[k] = ''.join(traceback.format_tb(v)) + elif isinstance(v, datetime.datetime): + kwargs[k] = timeutils.strtime(at=v) if hasattr(fn, '__call__'): return fn(obj, *args, **kwargs) # NOTE(danms): We wrap a descriptor, so use that protocol diff --git a/nova/tests/unit/objects/test_objects.py b/nova/tests/unit/objects/test_objects.py index 13b8dc8ad53a..37be4d29a0ff 100644 --- a/nova/tests/unit/objects/test_objects.py +++ b/nova/tests/unit/objects/test_objects.py @@ -1193,6 +1193,28 @@ class TestObjectSerializer(_BaseTestCase): self.assertIsInstance(thing2['foo'], base.NovaObject) +class TestArgsSerializer(test.NoDBTestCase): + def setUp(self): + super(TestArgsSerializer, self).setUp() + self.now = timeutils.utcnow() + self.str_now = timeutils.strtime(at=self.now) + + @base.serialize_args + def _test_serialize_args(self, *args, **kwargs): + expected_args = ('untouched', self.str_now, self.str_now) + for index, val in enumerate(args): + self.assertEqual(expected_args[index], val) + + expected_kwargs = {'a': 'untouched', 'b': self.str_now, + 'c': self.str_now} + for key, val in kwargs.iteritems(): + self.assertEqual(expected_kwargs[key], val) + + def test_serialize_args(self): + self._test_serialize_args('untouched', self.now, self.now, + a='untouched', b=self.now, c=self.now) + + # NOTE(danms): The hashes in this list should only be changed if # they come with a corresponding version bump in the affected # objects