From b3e8cb5b4236c39126d445c7645aed2922ab3991 Mon Sep 17 00:00:00 2001 From: Xiao Chen Date: Wed, 11 Sep 2013 14:37:16 +0800 Subject: [PATCH] Fixing UnicodeEncodeError against volume creating function When creating a volume with non-English characters and there is not enough space for it, then an UnicodeEncodeError occurs. So we need convert any coded exception message to unicode string for logging. Fixes bug 1223128 Change-Id: If1d4faad2bcde696f20565deb01226de33caccad --- cinder/tests/test_create_volume_flow.py | 21 +++++++++++++++++++ cinder/volume/flows/create_volume/__init__.py | 16 +++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/cinder/tests/test_create_volume_flow.py b/cinder/tests/test_create_volume_flow.py index e3e7452bd39..a3c550be5e0 100644 --- a/cinder/tests/test_create_volume_flow.py +++ b/cinder/tests/test_create_volume_flow.py @@ -79,6 +79,27 @@ class CreateVolumeFlowTestCase(test.TestCase): self.counter = float(0) self.stubs.Set(time, 'time', self.time_inc) + def test_exception_to_unicode(self): + class FakeException(Exception): + def __str__(self): + raise UnicodeError() + + exc = Exception('error message') + ret = create_volume._exception_to_unicode(exc) + self.assertEqual(unicode, type(ret)) + self.assertEqual(ret, 'error message') + + exc = Exception('\xa5 error message') + ret = create_volume._exception_to_unicode(exc) + self.assertEqual(unicode, type(ret)) + self.assertEqual(ret, ' error message') + + unicodeExc = FakeException('\xa5 error message') + ret = create_volume._exception_to_unicode(unicodeExc) + self.assertEqual(unicode, type(ret)) + self.assertEqual(ret, _("Caught '%(exception)s' exception.") % + {'exception': 'FakeException'}) + def test_cast_create_volume(self): props = {} diff --git a/cinder/volume/flows/create_volume/__init__.py b/cinder/volume/flows/create_volume/__init__.py index 391250a6f33..b0ea1c9cc59 100644 --- a/cinder/volume/flows/create_volume/__init__.py +++ b/cinder/volume/flows/create_volume/__init__.py @@ -30,6 +30,7 @@ from cinder.openstack.common import excutils from cinder.openstack.common import log as logging from cinder.openstack.common.notifier import api as notifier from cinder.openstack.common import processutils +from cinder.openstack.common import strutils from cinder.openstack.common import timeutils from cinder import policy from cinder import quota @@ -147,6 +148,18 @@ def _error_out_volume(context, db, volume_id, reason=None): 'update': update}) +def _exception_to_unicode(exc): + try: + return unicode(exc) + except UnicodeError: + try: + return strutils.safe_decode(str(exc), errors='ignore') + except UnicodeError: + msg = (_("Caught '%(exception)s' exception.") % + {"exception": exc.__class__.__name__}) + return strutils.safe_decode(msg, errors='ignore') + + class ExtractVolumeRequestTask(base.CinderTask): """Processes an api request values into a validated set of values. @@ -868,7 +881,8 @@ class OnFailureRescheduleTask(base.CinderTask): "attempt %(num)d due to %(reason)s") % {'volume_id': volume_id, 'method': _make_pretty_name(create_volume), - 'num': num_attempts, 'reason': unicode(cause.exc)}) + 'num': num_attempts, + 'reason': _exception_to_unicode(cause.exc)}) if all(cause.exc_info): # Stringify to avoid circular ref problem in json serialization