from neutron.api.v2 import attributes
from neutron.common import exceptions
+from neutron.openstack.common import gettextutils
from neutron.openstack.common import log as logging
from neutron import wsgi
action = args.pop('action', None)
content_type = format_types.get(fmt,
request.best_match_content_type())
+ language = request.best_match_language()
deserializer = deserializers.get(content_type)
serializer = serializers.get(content_type)
except (exceptions.NeutronException,
netaddr.AddrFormatError) as e:
LOG.exception(_('%s failed'), action)
+ e = translate(e, language)
body = serializer.serialize({'NeutronError': e})
kwargs = {'body': body, 'content_type': content_type}
for fault in faults:
raise webob.exc.HTTPInternalServerError(**kwargs)
except webob.exc.HTTPException as e:
LOG.exception(_('%s failed'), action)
+ translate(e, language)
e.body = serializer.serialize({'NeutronError': e})
e.content_type = content_type
raise
except NotImplementedError as e:
+ e = translate(e, language)
# NOTE(armando-migliaccio): from a client standpoint
# it makes sense to receive these errors, because
# extensions may or may not be implemented by
# Do not expose details of 500 error to clients.
msg = _('Request Failed: internal server error while '
'processing your request.')
+ msg = translate(msg, language)
body = serializer.serialize({'NeutronError': msg})
kwargs = {'body': body, 'content_type': content_type}
raise webob.exc.HTTPInternalServerError(**kwargs)
content_type=content_type,
body=body)
return resource
+
+
+def translate(translatable, locale):
+ """Translates the object to the given locale.
+
+ If the object is an exception its translatable elements are translated
+ in place, if the object is a translatable string it is translated and
+ returned. Otherwise, the object is returned as-is.
+
+ :param translatable: the object to be translated
+ :param locale: the locale to translate to
+ :returns: the translated object, or the object as-is if it
+ was not translated
+ """
+ localize = gettextutils.get_localized_message
+ if isinstance(translatable, Exception):
+ translatable.message = localize(translatable.message, locale)
+ if isinstance(translatable, webob.exc.HTTPError):
+ translatable.detail = localize(translatable.detail, locale)
+ return translatable
+ return localize(translatable, locale)
from neutron.common import config
from neutron import service
+from neutron.openstack.common import gettextutils
+gettextutils.install('neutron', lazy=True)
+
def main():
eventlet.monkey_patch()
from neutron.api.v2 import resource as wsgi_resource
from neutron.common import exceptions as q_exc
from neutron import context
+from neutron.openstack.common import gettextutils
from neutron.tests import base
from neutron import wsgi
def test_context_without_neutron_context(self):
self.assertTrue(self.req.context.is_admin)
+ def test_best_match_language(self):
+ # Here we test that we are actually invoking language negotiation
+ # by webop and also that the default locale always available is en-US
+ request = wsgi.Request.blank('/')
+ gettextutils.get_available_languages = mock.MagicMock()
+ gettextutils.get_available_languages.return_value = ['known-language',
+ 'es', 'zh']
+ request.headers['Accept-Language'] = 'known-language'
+ language = request.best_match_language()
+ self.assertEqual(language, 'known-language')
+ request.headers['Accept-Language'] = 'unknown-language'
+ language = request.best_match_language()
+ self.assertEqual(language, 'en_US')
+
class ResourceTestCase(base.BaseTestCase):
+
def test_unmapped_neutron_error_with_json(self):
msg = u'\u7f51\u7edc'
self.assertEqual(wsgi.XMLDeserializer().deserialize(res.body),
expected_res)
+ @mock.patch('neutron.openstack.common.gettextutils.Message.data',
+ new_callable=mock.PropertyMock)
+ def test_unmapped_neutron_error_localized(self, mock_translation):
+ gettextutils.install('blaa', lazy=True)
+ msg_translation = 'Translated error'
+ mock_translation.return_value = msg_translation
+ msg = _('Unmapped error')
+
+ class TestException(q_exc.NeutronException):
+ message = msg
+
+ controller = mock.MagicMock()
+ controller.test.side_effect = TestException()
+ resource = webtest.TestApp(wsgi_resource.Resource(controller))
+
+ environ = {'wsgiorg.routing_args': (None, {'action': 'test',
+ 'format': 'json'})}
+
+ res = resource.get('', extra_environ=environ, expect_errors=True)
+ self.assertEqual(res.status_int, exc.HTTPInternalServerError.code)
+ self.assertIn(msg_translation,
+ str(wsgi.JSONDeserializer().deserialize(res.body)))
+
def test_mapped_neutron_error_with_json(self):
msg = u'\u7f51\u7edc'
self.assertEqual(wsgi.XMLDeserializer().deserialize(res.body),
expected_res)
+ @mock.patch('neutron.openstack.common.gettextutils.Message.data',
+ new_callable=mock.PropertyMock)
+ def test_mapped_neutron_error_localized(self, mock_translation):
+ gettextutils.install('blaa', lazy=True)
+ msg_translation = 'Translated error'
+ mock_translation.return_value = msg_translation
+ msg = _('Unmapped error')
+
+ class TestException(q_exc.NeutronException):
+ message = msg
+
+ controller = mock.MagicMock()
+ controller.test.side_effect = TestException()
+ faults = {TestException: exc.HTTPGatewayTimeout}
+ resource = webtest.TestApp(wsgi_resource.Resource(controller,
+ faults=faults))
+
+ environ = {'wsgiorg.routing_args': (None, {'action': 'test',
+ 'format': 'json'})}
+
+ res = resource.get('', extra_environ=environ, expect_errors=True)
+ self.assertEqual(res.status_int, exc.HTTPGatewayTimeout.code)
+ self.assertIn(msg_translation,
+ str(wsgi.JSONDeserializer().deserialize(res.body)))
+
def test_http_error(self):
controller = mock.MagicMock()
controller.test.side_effect = exc.HTTPGatewayTimeout()
from neutron.common import constants
from neutron.common import exceptions as exception
from neutron import context
+from neutron.openstack.common import gettextutils
from neutron.openstack.common import jsonutils
from neutron.openstack.common import log as logging
return _type
return None
+ def best_match_language(self):
+ """Determine language for returned response."""
+ all_languages = gettextutils.get_available_languages('neutron')
+ return self.accept_language.best_match(all_languages,
+ default_match='en_US')
+
@property
def context(self):
if 'neutron.context' not in self.environ: