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
This commit is contained in:
Hans Lindgren 2015-04-15 11:42:32 +02:00
parent dde1c1e175
commit 83cdec4123
2 changed files with 31 additions and 9 deletions

View File

@ -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

View File

@ -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