From 4e036191ff127472293285f55bb1230f99946b82 Mon Sep 17 00:00:00 2001 From: Kirill Zaitsev Date: Thu, 19 Feb 2015 13:55:49 +0300 Subject: [PATCH] Use oslo.i18n for translation Remove gettextutils in favor of oslo.i18n suite for internationalization purposes. Wrap murano.common.i18n around oslo.i18n. Mark all logs messages of levels higher than DEBUG for translation with _/_LI/_LW/_LE/_LC to conform with oslo.i18n guidelines. Change-Id: I09a2e2fc802e404f5c59fa4edd2a2124ad24101a Implements: blueprint organize-translation --- murano/api/middleware/context.py | 2 +- murano/api/middleware/version_negotiation.py | 5 +- murano/api/v1/actions.py | 20 +- murano/api/v1/catalog.py | 34 +- murano/api/v1/deployments.py | 16 +- murano/api/v1/environments.py | 24 +- murano/api/v1/sessions.py | 2 +- murano/cmd/manage.py | 16 +- murano/common/config.py | 6 +- murano/common/engine.py | 13 +- murano/common/i18n.py | 34 ++ murano/common/policy.py | 11 +- murano/common/server.py | 10 +- murano/common/statservice.py | 6 +- murano/common/utils.py | 4 +- murano/common/wsgi.py | 14 +- murano/db/catalog/api.py | 16 +- murano/dsl/executor.py | 7 +- murano/engine/package_loader.py | 8 +- murano/engine/system/heat_stack.py | 5 +- murano/openstack/common/_i18n.py | 2 +- murano/openstack/common/exception.py | 2 +- murano/openstack/common/gettextutils.py | 498 ------------------ murano/openstack/common/log.py | 7 +- murano/openstack/common/processutils.py | 2 +- murano/policy/model_policy_enforcer.py | 13 +- .../unit/db/migration/test_migrations_base.py | 6 +- murano/utils.py | 24 +- openstack-common.conf | 1 - requirements.txt | 1 + tox.ini | 4 +- 31 files changed, 185 insertions(+), 628 deletions(-) create mode 100644 murano/common/i18n.py delete mode 100644 murano/openstack/common/gettextutils.py diff --git a/murano/api/middleware/context.py b/murano/api/middleware/context.py index da9a0b035..57c587753 100644 --- a/murano/api/middleware/context.py +++ b/murano/api/middleware/context.py @@ -14,9 +14,9 @@ from oslo.config import cfg +from murano.common.i18n import _ from murano.common import wsgi import murano.context -from murano.openstack.common.gettextutils import _ import murano.openstack.common.log as logging context_opts = [ diff --git a/murano/api/middleware/version_negotiation.py b/murano/api/middleware/version_negotiation.py index 004f7000b..36050537a 100644 --- a/murano/api/middleware/version_negotiation.py +++ b/murano/api/middleware/version_negotiation.py @@ -22,7 +22,6 @@ from oslo.config import cfg from murano.api import versions from murano.common import wsgi -from murano.openstack.common.gettextutils import _ import murano.openstack.common.log as logging CONF = cfg.CONF @@ -42,8 +41,8 @@ class VersionNegotiationFilter(wsgi.Middleware): def process_request(self, req): """Try to find a version first in the accept header, then the URL.""" - msg = _("Determining version of request: %(method)s %(path)s" - " Accept: %(accept)s") + msg = ("Determining version of request:" + " %(method)s %(path)s Accept: %(accept)s") args = {'method': req.method, 'path': req.path, 'accept': req.accept} LOG.debug(msg % args) diff --git a/murano/api/v1/actions.py b/murano/api/v1/actions.py index a873b0964..0ecacd432 100644 --- a/murano/api/v1/actions.py +++ b/murano/api/v1/actions.py @@ -20,7 +20,7 @@ from murano.db import models from murano.db.services import environments as envs from murano.db.services import sessions from murano.db import session as db_session -from murano.openstack.common.gettextutils import _ +from murano.common.i18n import _LI, _LE from murano.openstack.common import log as logging from murano.services import actions from murano.services import states @@ -39,30 +39,30 @@ class Controller(object): environment = unit.query(models.Environment).get(environment_id) if environment is None: - LOG.info(_('Environment ' - 'is not found').format(environment_id)) + LOG.info(_LI('Environment ' + 'is not found').format(environment_id)) raise exc.HTTPNotFound if environment.tenant_id != request.context.tenant: - LOG.info(_('User is not authorized to access ' - 'this tenant resources.')) + LOG.info(_LI('User is not authorized to access ' + 'this tenant resources.')) raise exc.HTTPUnauthorized # no new session can be opened if environment has deploying status env_status = envs.EnvironmentServices.get_status(environment_id) if env_status in (states.EnvironmentStatus.DEPLOYING, states.EnvironmentStatus.DELETING): - LOG.info(_('Could not open session for environment ,' - 'environment has deploying ' - 'status.').format(environment_id)) + LOG.info(_LI('Could not open session for environment ,' + 'environment has deploying ' + 'status.').format(environment_id)) raise exc.HTTPForbidden() user_id = request.context.user session = sessions.SessionServices.create(environment_id, user_id) if not sessions.SessionServices.validate(session): - LOG.error(_('Session ' - 'is invalid').format(session.id)) + LOG.error(_LE('Session ' + 'is invalid').format(session.id)) raise exc.HTTPForbidden() actions.ActionServices.execute(action_id, session, unit, diff --git a/murano/api/v1/catalog.py b/murano/api/v1/catalog.py index 8caa228ce..65d40a36b 100644 --- a/murano/api/v1/catalog.py +++ b/murano/api/v1/catalog.py @@ -27,8 +27,8 @@ from murano.api.v1 import schemas from murano.common import policy from murano.common import wsgi from murano.db.catalog import api as db_api +from murano.common.i18n import _, _LW from murano.openstack.common import exception -from murano.openstack.common.gettextutils import _ from murano.openstack.common import log as logging from murano.packages import exceptions as pkg_exc from murano.packages import load_utils @@ -57,8 +57,8 @@ def _get_filters(query_params): for param_pair in query_params: k, v = param_pair if k not in SUPPORTED_PARAMS: - LOG.warning(_("Search by parameter '{name}' " - "is not supported. Skipping it.").format(name=k)) + LOG.warning(_LW("Search by parameter '{name}' " + "is not supported. Skipping it.").format(name=k)) continue if k in LIST_PARAMS: @@ -69,9 +69,10 @@ def _get_filters(query_params): for i in order_by[:]: if ORDER_VALUES and i not in ORDER_VALUES: filters['order_by'].remove(i) - LOG.warning(_("Value of 'order_by' parameter is not valid. " - "Allowed values are: {0}. Skipping it.").format( - ", ".join(ORDER_VALUES))) + LOG.warning(_LW( + "Value of 'order_by' parameter is not valid. " + "Allowed values are: {0}. Skipping it.").format( + ", ".join(ORDER_VALUES))) return filters @@ -89,15 +90,16 @@ def _validate_body(body): size = f.tell() f.seek(0) if size > pkg_size_limit: - raise exc.HTTPBadRequest('Uploading file is too large.' - ' The limit is {0} Mb'.format(mb_limit)) + raise exc.HTTPBadRequest(explanation=_( + 'Uploading file is too large.' + ' The limit is {0} Mb').format(mb_limit)) if len(body.keys()) > 2: msg = _("'multipart/form-data' request body should contain " "1 or 2 parts: json string and zip archive. Current body " "consists of {0} part(s)").format(len(body.keys())) LOG.error(msg) - raise exc.HTTPBadRequest(msg) + raise exc.HTTPBadRequest(explanation=msg) file_obj = None package_meta = None @@ -111,7 +113,7 @@ def _validate_body(body): if file_obj is None: msg = _('There is no file package with application description') LOG.error(msg) - raise exc.HTTPBadRequest(msg) + raise exc.HTTPBadRequest(explanation=msg) return file_obj, package_meta @@ -192,8 +194,9 @@ class Controller(object): try: jsonschema.validate(package_meta, schemas.PKG_UPLOAD_SCHEMA) except jsonschema.ValidationError as e: - LOG.exception(e) - raise exc.HTTPBadRequest(explanation=e.message) + msg = _("Package schema is not valid: {0}").format(e) + LOG.exception(msg) + raise exc.HTTPBadRequest(explanation=msg) else: package_meta = {} @@ -203,15 +206,16 @@ class Controller(object): if not content: msg = _("Uploading file can't be empty") LOG.error(msg) - raise exc.HTTPBadRequest(msg) + raise exc.HTTPBadRequest(explanation=msg) tempf.write(content) package_meta['archive'] = content try: pkg_to_upload = load_utils.load_from_file( tempf.name, target_dir=None, drop_dir=True) except pkg_exc.PackageLoadError as e: - LOG.exception(e) - raise exc.HTTPBadRequest(e) + msg = _("Couldn't load package from file: {0}").format(e) + LOG.exception(msg) + raise exc.HTTPBadRequest(explanation=msg) finally: LOG.debug("Deleting package archive temporary file") os.remove(tempf.name) diff --git a/murano/api/v1/deployments.py b/murano/api/v1/deployments.py index 0cd2033a1..3088554e1 100644 --- a/murano/api/v1/deployments.py +++ b/murano/api/v1/deployments.py @@ -16,12 +16,12 @@ from webob import exc from murano.api.v1 import request_statistics from murano.common.helpers import token_sanitizer +from murano.common.i18n import _LI from murano.common import policy from murano.common import utils from murano.common import wsgi from murano.db import models from murano.db import session as db_session -from murano.openstack.common.gettextutils import _ from murano.openstack.common import log as logging LOG = logging.getLogger(__name__) @@ -81,11 +81,13 @@ class Controller(object): def verify_and_get_env(db_session, environment_id, request): environment = db_session.query(models.Environment).get(environment_id) if not environment: - LOG.info(_('Environment with id {0} not found').format(environment_id)) + LOG.info(_LI( + 'Environment with id {0} not found').format(environment_id)) raise exc.HTTPNotFound if environment.tenant_id != request.context.tenant: - LOG.info(_('User is not authorized to access this tenant resources.')) + LOG.info(_LI( + 'User is not authorized to access this tenant resources.')) raise exc.HTTPUnauthorized return environment @@ -98,12 +100,12 @@ def _patch_description(description): def verify_and_get_deployment(db_session, environment_id, deployment_id): deployment = db_session.query(models.Task).get(deployment_id) if not deployment: - LOG.info(_('Deployment with id {0} not found').format(deployment_id)) + LOG.info(_LI('Deployment with id {0} not found').format(deployment_id)) raise exc.HTTPNotFound if deployment.environment_id != environment_id: - LOG.info(_('Deployment with id {0} not found' - ' in environment {1}').format(deployment_id, - environment_id)) + LOG.info(_LI('Deployment with id {0} not found' + ' in environment {1}').format(deployment_id, + environment_id)) raise exc.HTTPBadRequest deployment.description = _patch_description(deployment.description) diff --git a/murano/api/v1/environments.py b/murano/api/v1/environments.py index 8192716ea..e47bc2c1e 100644 --- a/murano/api/v1/environments.py +++ b/murano/api/v1/environments.py @@ -27,7 +27,7 @@ from murano.db import models from murano.db.services import core_services from murano.db.services import environments as envs from murano.db import session as db_session -from murano.openstack.common.gettextutils import _ +from murano.common.i18n import _, _LI from murano.openstack.common import log as logging LOG = logging.getLogger(__name__) @@ -63,12 +63,12 @@ class Controller(object): except db_exc.DBDuplicateEntry: msg = _('Environment with specified name already exists') LOG.exception(msg) - raise exc.HTTPConflict(msg) + raise exc.HTTPConflict(explanation=msg) else: msg = _('Environment name must contain only alphanumeric ' 'or "_-." characters, must start with alpha') LOG.exception(msg) - raise exc.HTTPClientError(msg) + raise exc.HTTPClientError(explanation=msg) return environment.to_dict() @@ -82,13 +82,13 @@ class Controller(object): environment = session.query(models.Environment).get(environment_id) if environment is None: - LOG.info(_('Environment is not found').format( + LOG.info(_LI('Environment is not found').format( environment_id)) raise exc.HTTPNotFound if environment.tenant_id != request.context.tenant: - LOG.info(_('User is not authorized to access ' - 'this tenant resources.')) + LOG.info(_LI('User is not authorized to access ' + 'this tenant resources.')) raise exc.HTTPUnauthorized env = environment.to_dict() @@ -115,13 +115,13 @@ class Controller(object): environment = session.query(models.Environment).get(environment_id) if environment is None: - LOG.info(_('Environment is not ' - 'found').format(environment_id)) + LOG.info(_LI('Environment not ' + 'found').format(environment_id)) raise exc.HTTPNotFound if environment.tenant_id != request.context.tenant: - LOG.info(_('User is not authorized to access ' - 'this tenant resources.')) + LOG.info(_LI('User is not authorized to access ' + 'this tenant resources.')) raise exc.HTTPUnauthorized LOG.debug('ENV NAME: {0}>'.format(body['name'])) @@ -131,8 +131,8 @@ class Controller(object): else: msg = _('Environment name must contain only alphanumeric ' 'or "_-." characters, must start with alpha') - LOG.exception(msg) - raise exc.HTTPClientError(msg) + LOG.error(msg) + raise exc.HTTPClientError(explanation=msg) return environment.to_dict() diff --git a/murano/api/v1/sessions.py b/murano/api/v1/sessions.py index 299a32124..4d80e8c97 100644 --- a/murano/api/v1/sessions.py +++ b/murano/api/v1/sessions.py @@ -15,12 +15,12 @@ from webob import exc from murano.api.v1 import request_statistics +from murano.common.i18n import _ from murano.common import wsgi from murano.db import models from murano.db.services import environments as envs from murano.db.services import sessions from murano.db import session as db_session -from murano.openstack.common.gettextutils import _ from murano.openstack.common import log as logging from murano.services import states diff --git a/murano/cmd/manage.py b/murano/cmd/manage.py index 2d1653430..45f3fb6c4 100644 --- a/murano/cmd/manage.py +++ b/murano/cmd/manage.py @@ -26,6 +26,7 @@ from oslo.db import exception as db_exception from murano.common import consts from murano.db.catalog import api as db_catalog_api +from murano.common.i18n import _LI, _LE from murano.openstack.common import log as logging from murano.packages import load_utils from murano import version @@ -40,20 +41,21 @@ class AdminContext(object): def _do_import_package(_dir, categories, update=False): - LOG.info("Going to import Murano package from {0}".format(_dir)) + LOG.info(_LI("Going to import Murano package from {0}").format(_dir)) pkg = load_utils.load_from_dir(_dir) - LOG.info("Checking for existing") + LOG.info(_LI("Checking for existing")) existing = db_catalog_api.package_search( {'fqn': pkg.full_name}, AdminContext()) if existing: existing_pkg = existing[0] if update: - LOG.info("Deleting existing package {0}".format(existing_pkg.id)) + LOG.info(_LI( + "Deleting existing package {0}").format(existing_pkg.id)) db_catalog_api.package_delete(existing_pkg.id, AdminContext()) else: - LOG.error("Package '{0}' exists ({1}). Use --update.".format( + LOG.error(_LE("Package '{0}' exists ({1}). Use --update.").format( pkg.full_name, existing_pkg.id)) return @@ -81,7 +83,7 @@ def _do_import_package(_dir, categories, update=False): # it is a required field in the DB, that's why we pass an empty string result = db_catalog_api.package_upload(package, '') - LOG.info("Finished import of package {0}".format(result.id)) + LOG.info(_LI("Finished import of package {0}").format(result.id)) # TODO(ruhe): proper error handling @@ -154,14 +156,14 @@ def main(): default_config_files=default_config_files) logging.setup("murano") except RuntimeError as e: - LOG.error("failed to initialize murano-manage: %s" % e) + LOG.error(_LE("failed to initialize murano-manage: %s") % e) sys.exit("ERROR: %s" % e) try: CONF.command.func() except Exception as e: tb = traceback.format_exc() - err_msg = "murano-manage command failed: {0}\n{1}".format(e, tb) + err_msg = _LE("murano-manage command failed: {0}\n{1}").format(e, tb) LOG.error(err_msg) sys.exit(err_msg) diff --git a/murano/common/config.py b/murano/common/config.py index 624c9c5cc..dec2a8e70 100644 --- a/murano/common/config.py +++ b/murano/common/config.py @@ -25,7 +25,7 @@ import sys from oslo.config import cfg from paste import deploy -from murano.openstack.common.gettextutils import _ +from murano.common.i18n import _ from murano import version paste_deploy_opts = [ @@ -343,8 +343,8 @@ def load_paste_app(app_name=None): try: logger = logging.getLogger(__name__) - logger.debug(_("Loading %(app_name)s from %(conf_file)s"), - {'conf_file': conf_file, 'app_name': app_name}) + logger.debug("Loading %(app_name)s from %(conf_file)s".format( + conf_file=conf_file, app_name=app_name)) app = deploy.loadapp("config:%s" % conf_file, name=app_name) diff --git a/murano/common/engine.py b/murano/common/engine.py index b28d05f07..a0a184833 100644 --- a/murano/common/engine.py +++ b/murano/common/engine.py @@ -33,7 +33,7 @@ from murano.engine import package_class_loader from murano.engine import package_loader from murano.engine.system import status_reporter import murano.engine.system.system_objects as system_objects -from murano.openstack.common.gettextutils import _ +from murano.common.i18n import _LI, _LE from murano.openstack.common import log as logging from murano.policy import model_policy_enforcer as enforcer @@ -48,7 +48,7 @@ class TaskProcessingEndpoint(object): @staticmethod def handle_task(context, task): s_task = token_sanitizer.TokenSanitizer().sanitize(task) - LOG.info(_('Starting processing task: {task_desc}').format( + LOG.info(_LI('Starting processing task: {task_desc}').format( task_desc=jsonutils.dumps(s_task))) result = task['model'] @@ -56,7 +56,7 @@ class TaskProcessingEndpoint(object): task_executor = TaskExecutor(task) result = task_executor.execute() except Exception as e: - LOG.exception('Error during task execution for tenant %s', + LOG.exception(_LE('Error during task execution for tenant %s'), task['tenant_id']) msg_env = Environment(task['id']) reporter = status_reporter.StatusReporter() @@ -135,7 +135,7 @@ class TaskExecutor(object): self._validate_model(obj, self.action, class_loader) try: - # Skip execution of action in case of no action is provided. + # Skip execution of action in case no action is provided. # Model will be just loaded, cleaned-up and unloaded. # Most of the time this is used for deletion of environments. if self.action: @@ -144,7 +144,10 @@ class TaskExecutor(object): if isinstance(e, dsl_exception.MuranoPlException): LOG.error('\n' + e.format(prefix=' ')) else: - LOG.exception(e) + LOG.exception( + _LE("Exception %(exc)s occured" + " during invocation of %(method)"), + {'exc': e, 'method': self.action['method']}) reporter = status_reporter.StatusReporter() reporter.initialize(obj) reporter.report_error(obj, str(e)) diff --git a/murano/common/i18n.py b/murano/common/i18n.py new file mode 100644 index 000000000..676643704 --- /dev/null +++ b/murano/common/i18n.py @@ -0,0 +1,34 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +"""oslo.i18n integration module. + +See http://docs.openstack.org/developer/oslo.i18n/usage.html + +""" + +import oslo_i18n + +_translators = oslo_i18n.TranslatorFactory(domain='murano') + +# The primary translation function using the well-known name "_" +_ = _translators.primary + +# Translators for log levels. +# +# The abbreviated names are meant to reflect the usual use of a short +# name like '_'. The "L" is for "log" and the other letter comes from +# the level. +_LI = _translators.log_info +_LW = _translators.log_warning +_LE = _translators.log_error +_LC = _translators.log_critical diff --git a/murano/common/policy.py b/murano/common/policy.py index 9ea2b49a0..fd447bb00 100644 --- a/murano/common/policy.py +++ b/murano/common/policy.py @@ -17,6 +17,7 @@ from oslo.config import cfg from webob import exc as exceptions +from murano.common.i18n import _ import murano.openstack.common.log as logging from murano.openstack.common import policy @@ -77,8 +78,10 @@ def check(rule, ctxt, target={}, do_raise=True, exc=exceptions.HTTPForbidden): extra = {'policy': {'rule': rule, 'target': target}} if result: - LOG.audit("Policy check succeeded for rule '%s' on target %s", - rule, repr(target), extra=extra) + LOG.audit(_("Policy check succeeded for rule " + "'%(rule)s' on target %(target)s"), + {'rule': rule, 'target': repr(target)}, extra=extra) else: - LOG.audit("Policy check failed for rule '%s' on target: %s", - rule, repr(target), extra=extra) + LOG.audit(_("Policy check failed for rule " + "'%(rule)s' on target: %(target)s"), + {'rule': rule, 'target': repr(target)}, extra=extra) diff --git a/murano/common/server.py b/murano/common/server.py index 209ea3c72..c59ff9897 100644 --- a/murano/common/server.py +++ b/murano/common/server.py @@ -26,7 +26,7 @@ from murano.db import models from murano.db.services import environments from murano.db.services import instances from murano.db import session -from murano.openstack.common.gettextutils import _ +from murano.common.i18n import _, _LI, _LW from murano.openstack.common import log as logging from murano.services import states @@ -48,8 +48,8 @@ class ResultEndpoint(object): environment = unit.query(models.Environment).get(environment_id) if not environment: - LOG.warning(_('Environment result could not be handled, specified ' - 'environment was not found in database')) + LOG.warning(_LW('Environment result could not be handled, ' + 'specified environment not found in database')) return if result['Objects'] is None and result.get('ObjectsCopy', {}) is None: @@ -106,10 +106,10 @@ class ResultEndpoint(object): conf_session.save(unit) # output application tracking information - message = ''.format( + message = _LI('EnvId: {0} TenantId: {1} Status: {2} Apps: {3}').format( environment.id, environment.tenant_id, - 'Failed' if num_errors + num_warnings > 0 else 'Successful', + _('Failed') if num_errors + num_warnings > 0 else _('Successful'), ', '.join(map( lambda a: a['?']['type'], result['Objects']['services'] diff --git a/murano/common/statservice.py b/murano/common/statservice.py index 84a73a9d3..8c9f0eb6f 100644 --- a/murano/common/statservice.py +++ b/murano/common/statservice.py @@ -23,8 +23,8 @@ import psutil from murano.api import v1 from murano.api.v1 import request_statistics from murano.common import config +from murano.common.i18n import _LE from murano.db.services import stats as db_stats -from murano.openstack.common.gettextutils import _ from murano.openstack.common import log as logging from murano.openstack.common import service @@ -92,5 +92,5 @@ class StatsCollectingService(service.Service): stats.cpu_percent = psutil.cpu_percent() self._stats_db.update(self._hostname, stats) except Exception as e: - LOG.error(_("Failed to get statistics object " - "form a database. {0}").format(e)) + LOG.exception(_LE("Failed to get statistics object " + "form a database. %s"), e) diff --git a/murano/common/utils.py b/murano/common/utils.py index bd98867ef..59805a9db 100644 --- a/murano/common/utils.py +++ b/murano/common/utils.py @@ -19,7 +19,7 @@ import types import eventlet import jsonschema -from murano.openstack.common.gettextutils import _ +from murano.common.i18n import _, _LI from murano.openstack.common import log as logging @@ -240,7 +240,7 @@ def retry(ExceptionToCheck, tries=4, delay=3, backoff=2): except ExceptionToCheck as e: LOG.exception(e) - LOG.info(_("Retrying in {0} seconds...").format(mdelay)) + LOG.info(_LI("Retrying in {0} seconds...").format(mdelay)) eventlet.sleep(mdelay) diff --git a/murano/common/wsgi.py b/murano/common/wsgi.py index 4e1fd2f39..b641ba6b2 100644 --- a/murano/common/wsgi.py +++ b/murano/common/wsgi.py @@ -36,9 +36,9 @@ import webob.dec import webob.exc from murano.api.v1 import schemas +from murano.common.i18n import _ from murano.common import xmlutils from murano.openstack.common import exception -from murano.openstack.common.gettextutils import _ from murano.openstack.common import log as logging from murano.openstack.common import service from murano.openstack.common import sslutils @@ -660,24 +660,24 @@ class RequestDeserializer(object): def deserialize_body(self, request, action): if not len(request.body) > 0: - LOG.debug(_("Empty body provided in request")) + LOG.debug("Empty body provided in request") return {} try: content_type = request.get_content_type() except exception.InvalidContentType as e: - msg = _("Unrecognized Content-Type provided in request: {0}") + msg = "Unrecognized Content-Type provided in request: {0}" LOG.debug(unicode(msg).format(str(e))) raise if content_type is None: - LOG.debug(_("No Content-Type provided in request")) + LOG.debug("No Content-Type provided in request") return {} try: deserializer = self.get_body_deserializer(content_type) except exception.InvalidContentType: - LOG.debug(_("Unable to deserialize body as provided Content-Type")) + LOG.debug("Unable to deserialize body as provided Content-Type") raise return deserializer.deserialize(request, action) @@ -939,10 +939,10 @@ class FormDataDeserializer(TextDeserializer): def _from_json(self, datastring): value = datastring try: - LOG.debug(_("Trying deserialize '{0}' to json").format(datastring)) + LOG.debug("Trying deserialize '{0}' to json".format(datastring)) value = jsonutils.loads(datastring) except ValueError: - LOG.debug(_("Unable deserialize to json, using raw text")) + LOG.debug("Unable deserialize to json, using raw text") return value def default(self, request): diff --git a/murano/db/catalog/api.py b/murano/db/catalog/api.py index 1a23b76f6..a2b869ded 100644 --- a/murano/db/catalog/api.py +++ b/murano/db/catalog/api.py @@ -21,7 +21,7 @@ from webob import exc from murano.db import models from murano.db import session as db_session -from murano.openstack.common.gettextutils import _ +from murano.common.i18n import _, _LW from murano.openstack.common import log as logging CONF = cfg.CONF @@ -54,7 +54,7 @@ def _package_get(package_id_or_name, session): msg = _("Package id or name '{0}' not found").\ format(package_id_or_name) LOG.error(msg) - raise exc.HTTPNotFound(msg) + raise exc.HTTPNotFound(explanation=msg) return package @@ -68,12 +68,12 @@ def _authorize_package(package, context, allow_public=False): msg = _("Package '{0}' is not owned by " "tenant '{1}'").format(package.id, context.tenant) LOG.error(msg) - raise exc.HTTPForbidden(msg) + raise exc.HTTPForbidden(explanation=msg) if not package.is_public: msg = _("Package '{0}' is not public and not owned by " "tenant '{1}' ").format(package.id, context.tenant) LOG.error(msg) - raise exc.HTTPForbidden(msg) + raise exc.HTTPForbidden(explanation=msg) def package_get(package_id_or_name, context): @@ -104,7 +104,7 @@ def _get_categories(category_names, session=None): msg = _("Category '{name}' doesn't exist").format(name=ctg_name) LOG.error(msg) # it's not allowed to specify non-existent categories - raise exc.HTTPBadRequest(msg) + raise exc.HTTPBadRequest(explanation=msg) categories.append(ctg_obj) return categories @@ -174,8 +174,8 @@ def _do_add(package, change): try: getattr(package, path).append(item) except AssertionError: - msg = _('One of the specified {0} is already ' - 'associated with a package. Doing nothing.') + msg = _LW('One of the specified {0} is already ' + 'associated with a package. Doing nothing.') LOG.warning(msg.format(path)) return package @@ -196,7 +196,7 @@ def _do_remove(package, change): msg = _("Value '{0}' of property '{1}' " "does not exist.").format(value, path) LOG.error(msg) - raise exc.HTTPNotFound(msg) + raise exc.HTTPNotFound(explanation=msg) item_to_remove = find(current_values, lambda i: i.name == value) current_values.remove(item_to_remove) return package diff --git a/murano/dsl/executor.py b/murano/dsl/executor.py index 4f30c969e..b9510e64c 100644 --- a/murano/dsl/executor.py +++ b/murano/dsl/executor.py @@ -22,6 +22,7 @@ import eventlet import eventlet.event import yaql.context +from murano.common.i18n import _ import murano.dsl.attribute_store as attribute_store import murano.dsl.dsl_exception as dsl_exception import murano.dsl.expressions as expressions @@ -86,9 +87,9 @@ class MuranoDslExecutor(object): # TODO(slagun): check method accessibility from murano_class if not external_call and is_special_method: - LOG.deprecated('initialize/destroy methods are called ' - 'automatically by engine. This call is no-op ' - 'and will become exception in the future') + LOG.deprecated(_('initialize/destroy methods are called ' + 'automatically by engine. This call is no-op ' + 'and will become exception in the future')) return None # restore this from upcast object (no change if there was no upcast) diff --git a/murano/engine/package_loader.py b/murano/engine/package_loader.py index 6af9cb544..8a9297f66 100644 --- a/murano/engine/package_loader.py +++ b/murano/engine/package_loader.py @@ -24,6 +24,7 @@ from muranoclient.common import exceptions as muranoclient_exc import six from murano.common import config +from murano.common.i18n import _LE from murano.dsl import exceptions from murano.engine import yaql_yaml_loader from murano.openstack.common import log as logging @@ -106,7 +107,8 @@ class ApiPackageLoader(PackageLoader): package_directory, preload=True, loader=yaql_yaml_loader.YaqlYamlLoader) except pkg_exc.PackageLoadError: - LOG.exception('Unable to load package from cache. Clean-up...') + LOG.exception(_LE( + 'Unable to load package from cache. Clean-up...')) shutil.rmtree(package_directory, ignore_errors=True) try: package_data = self._murano_client_factory().packages.download( @@ -176,8 +178,8 @@ class DirectoryPackageLoader(PackageLoader): folder, preload=True, loader=yaql_yaml_loader.YaqlYamlLoader) except pkg_exc.PackageLoadError: - LOG.exception('Unable to load package from path: ' - '{0}'.format(entry)) + LOG.exception(_LE('Unable to load package from path: ' + '{0}').format(entry)) continue for c in package.classes: diff --git a/murano/engine/system/heat_stack.py b/murano/engine/system/heat_stack.py index d0c4020f8..90a3592b1 100644 --- a/murano/engine/system/heat_stack.py +++ b/murano/engine/system/heat_stack.py @@ -22,6 +22,7 @@ import murano.common.utils as utils import murano.dsl.helpers as helpers import murano.dsl.murano_class as murano_class import murano.dsl.murano_object as murano_object +from murano.common.i18n import _LI, _LW import murano.openstack.common.log as logging LOG = logging.getLogger(__name__) @@ -162,7 +163,7 @@ class HeatStack(murano_object.MuranoObject): self._template['description'] = self._description template = copy.deepcopy(self._template) - LOG.info('Pushing: {0}'.format(template)) + LOG.info(_LI('Pushing: {0}').format(template)) current_status = self._get_status(_context) resources = template.get('Resources') or template.get('resources') @@ -204,7 +205,7 @@ class HeatStack(murano_object.MuranoObject): _context, lambda status: status in ('DELETE_COMPLETE', 'NOT_FOUND')) except heat_exc.NotFound: - LOG.warn('Stack {0} already deleted?'.format(self._name)) + LOG.warn(_LW('Stack {0} already deleted?').format(self._name)) self._template = {} self._applied = True diff --git a/murano/openstack/common/_i18n.py b/murano/openstack/common/_i18n.py index ad8f739d1..df0f31f5a 100644 --- a/murano/openstack/common/_i18n.py +++ b/murano/openstack/common/_i18n.py @@ -40,6 +40,6 @@ try: _LC = _translators.log_critical except ImportError: # NOTE(dims): Support for cases where a project wants to use - # code from murano-incubator, but is not ready to be internationalized + # code from oslo-incubator, but is not ready to be internationalized # (like tempest) _ = _LI = _LW = _LE = _LC = lambda x: x diff --git a/murano/openstack/common/exception.py b/murano/openstack/common/exception.py index f051dba8e..10d6776c1 100644 --- a/murano/openstack/common/exception.py +++ b/murano/openstack/common/exception.py @@ -21,7 +21,7 @@ Exceptions common to OpenStack projects import logging -from murano.openstack.common.gettextutils import _ # noqa +from murano.openstack.common._i18n import _ _FATAL_EXCEPTION_FORMAT_ERRORS = False diff --git a/murano/openstack/common/gettextutils.py b/murano/openstack/common/gettextutils.py deleted file mode 100644 index 2a8ab1bda..000000000 --- a/murano/openstack/common/gettextutils.py +++ /dev/null @@ -1,498 +0,0 @@ -# Copyright 2012 Red Hat, Inc. -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -""" -gettext for openstack-common modules. - -Usual usage in an openstack.common module: - - from murano.openstack.common.gettextutils import _ -""" - -import copy -import functools -import gettext -import locale -from logging import handlers -import os - -from babel import localedata -import six - -_AVAILABLE_LANGUAGES = {} - -# FIXME(dhellmann): Remove this when moving to oslo.i18n. -USE_LAZY = False - - -class TranslatorFactory(object): - """Create translator functions - """ - - def __init__(self, domain, lazy=False, localedir=None): - """Establish a set of translation functions for the domain. - - :param domain: Name of translation domain, - specifying a message catalog. - :type domain: str - :param lazy: Delays translation until a message is emitted. - Defaults to False. - :type lazy: Boolean - :param localedir: Directory with translation catalogs. - :type localedir: str - """ - self.domain = domain - self.lazy = lazy - if localedir is None: - localedir = os.environ.get(domain.upper() + '_LOCALEDIR') - self.localedir = localedir - - def _make_translation_func(self, domain=None): - """Return a new translation function ready for use. - - Takes into account whether or not lazy translation is being - done. - - The domain can be specified to override the default from the - factory, but the localedir from the factory is always used - because we assume the log-level translation catalogs are - installed in the same directory as the main application - catalog. - - """ - if domain is None: - domain = self.domain - if self.lazy: - return functools.partial(Message, domain=domain) - t = gettext.translation( - domain, - localedir=self.localedir, - fallback=True, - ) - if six.PY3: - return t.gettext - return t.ugettext - - @property - def primary(self): - "The default translation function." - return self._make_translation_func() - - def _make_log_translation_func(self, level): - return self._make_translation_func(self.domain + '-log-' + level) - - @property - def log_info(self): - "Translate info-level log messages." - return self._make_log_translation_func('info') - - @property - def log_warning(self): - "Translate warning-level log messages." - return self._make_log_translation_func('warning') - - @property - def log_error(self): - "Translate error-level log messages." - return self._make_log_translation_func('error') - - @property - def log_critical(self): - "Translate critical-level log messages." - return self._make_log_translation_func('critical') - - -# NOTE(dhellmann): When this module moves out of the incubator into -# oslo.i18n, these global variables can be moved to an integration -# module within each application. - -# Create the global translation functions. -_translators = TranslatorFactory('murano') - -# The primary translation function using the well-known name "_" -_ = _translators.primary - -# Translators for log levels. -# -# The abbreviated names are meant to reflect the usual use of a short -# name like '_'. The "L" is for "log" and the other letter comes from -# the level. -_LI = _translators.log_info -_LW = _translators.log_warning -_LE = _translators.log_error -_LC = _translators.log_critical - -# NOTE(dhellmann): End of globals that will move to the application's -# integration module. - - -def enable_lazy(): - """Convenience function for configuring _() to use lazy gettext - - Call this at the start of execution to enable the gettextutils._ - function to use lazy gettext functionality. This is useful if - your project is importing _ directly instead of using the - gettextutils.install() way of importing the _ function. - """ - # FIXME(dhellmann): This function will be removed in oslo.i18n, - # because the TranslatorFactory makes it superfluous. - global _, _LI, _LW, _LE, _LC, USE_LAZY - tf = TranslatorFactory('murano', lazy=True) - _ = tf.primary - _LI = tf.log_info - _LW = tf.log_warning - _LE = tf.log_error - _LC = tf.log_critical - USE_LAZY = True - - -def install(domain, lazy=False): - """Install a _() function using the given translation domain. - - Given a translation domain, install a _() function using gettext's - install() function. - - The main difference from gettext.install() is that we allow - overriding the default localedir (e.g. /usr/share/locale) using - a translation-domain-specific environment variable (e.g. - NOVA_LOCALEDIR). - - :param domain: the translation domain - :param lazy: indicates whether or not to install the lazy _() function. - The lazy _() introduces a way to do deferred translation - of messages by installing a _ that builds Message objects, - instead of strings, which can then be lazily translated into - any available locale. - """ - if lazy: - from six import moves - tf = TranslatorFactory(domain, lazy=True) - moves.builtins.__dict__['_'] = tf.primary - else: - localedir = '%s_LOCALEDIR' % domain.upper() - if six.PY3: - gettext.install(domain, - localedir=os.environ.get(localedir)) - else: - gettext.install(domain, - localedir=os.environ.get(localedir), - unicode=True) - - -class Message(six.text_type): - """A Message object is a unicode object that can be translated. - - Translation of Message is done explicitly using the translate() method. - For all non-translation intents and purposes, a Message is simply unicode, - and can be treated as such. - """ - - def __new__(cls, msgid, msgtext=None, params=None, - domain='murano', *args): - """Create a new Message object. - - In order for translation to work gettext requires a message ID, this - msgid will be used as the base unicode text. It is also possible - for the msgid and the base unicode text to be different by passing - the msgtext parameter. - """ - # If the base msgtext is not given, we use the default translation - # of the msgid (which is in English) just in case the system locale is - # not English, so that the base text will be in that locale by default. - if not msgtext: - msgtext = Message._translate_msgid(msgid, domain) - # We want to initialize the parent unicode with the actual object that - # would have been plain unicode if 'Message' was not enabled. - msg = super(Message, cls).__new__(cls, msgtext) - msg.msgid = msgid - msg.domain = domain - msg.params = params - return msg - - def translate(self, desired_locale=None): - """Translate this message to the desired locale. - - :param desired_locale: The desired locale to translate the message to, - if no locale is provided the message will be - translated to the system's default locale. - - :returns: the translated message in unicode - """ - - translated_message = Message._translate_msgid(self.msgid, - self.domain, - desired_locale) - if self.params is None: - # No need for more translation - return translated_message - - # This Message object may have been formatted with one or more - # Message objects as substitution arguments, given either as a single - # argument, part of a tuple, or as one or more values in a dictionary. - # When translating this Message we need to translate those Messages too - translated_params = _translate_args(self.params, desired_locale) - - translated_message = translated_message % translated_params - - return translated_message - - @staticmethod - def _translate_msgid(msgid, domain, desired_locale=None): - if not desired_locale: - system_locale = locale.getdefaultlocale() - # If the system locale is not available to the runtime use English - if not system_locale[0]: - desired_locale = 'en_US' - else: - desired_locale = system_locale[0] - - locale_dir = os.environ.get(domain.upper() + '_LOCALEDIR') - lang = gettext.translation(domain, - localedir=locale_dir, - languages=[desired_locale], - fallback=True) - if six.PY3: - translator = lang.gettext - else: - translator = lang.ugettext - - translated_message = translator(msgid) - return translated_message - - def __mod__(self, other): - # When we mod a Message we want the actual operation to be performed - # by the parent class (i.e. unicode()), the only thing we do here is - # save the original msgid and the parameters in case of a translation - params = self._sanitize_mod_params(other) - unicode_mod = super(Message, self).__mod__(params) - modded = Message(self.msgid, - msgtext=unicode_mod, - params=params, - domain=self.domain) - return modded - - def _sanitize_mod_params(self, other): - """Sanitize the object being modded with this Message. - - - Add support for modding 'None' so translation supports it - - Trim the modded object, which can be a large dictionary, to only - those keys that would actually be used in a translation - - Snapshot the object being modded, in case the message is - translated, it will be used as it was when the Message was created - """ - if other is None: - params = (other,) - elif isinstance(other, dict): - # Merge the dictionaries - # Copy each item in case one does not support deep copy. - params = {} - if isinstance(self.params, dict): - for key, val in self.params.items(): - params[key] = self._copy_param(val) - for key, val in other.items(): - params[key] = self._copy_param(val) - else: - params = self._copy_param(other) - return params - - def _copy_param(self, param): - try: - return copy.deepcopy(param) - except Exception: - # Fallback to casting to unicode this will handle the - # python code-like objects that can't be deep-copied - return six.text_type(param) - - def __add__(self, other): - msg = _('Message objects do not support addition.') - raise TypeError(msg) - - def __radd__(self, other): - return self.__add__(other) - - if six.PY2: - def __str__(self): - # NOTE(luisg): Logging in python 2.6 tries to str() log records, - # and it expects specifically a UnicodeError in order to proceed. - msg = _('Message objects do not support str() because they may ' - 'contain non-ascii characters. ' - 'Please use unicode() or translate() instead.') - raise UnicodeError(msg) - - -def get_available_languages(domain): - """Lists the available languages for the given translation domain. - - :param domain: the domain to get languages for - """ - if domain in _AVAILABLE_LANGUAGES: - return copy.copy(_AVAILABLE_LANGUAGES[domain]) - - localedir = '%s_LOCALEDIR' % domain.upper() - find = lambda x: gettext.find(domain, - localedir=os.environ.get(localedir), - languages=[x]) - - # NOTE(mrodden): en_US should always be available (and first in case - # order matters) since our in-line message strings are en_US - language_list = ['en_US'] - # NOTE(luisg): Babel <1.0 used a function called list(), which was - # renamed to locale_identifiers() in >=1.0, the requirements master list - # requires >=0.9.6, uncapped, so defensively work with both. We can remove - # this check when the master list updates to >=1.0, and update all projects - list_identifiers = (getattr(localedata, 'list', None) or - getattr(localedata, 'locale_identifiers')) - locale_identifiers = list_identifiers() - - for i in locale_identifiers: - if find(i) is not None: - language_list.append(i) - - # NOTE(luisg): Babel>=1.0,<1.3 has a bug where some OpenStack supported - # locales (e.g. 'zh_CN', and 'zh_TW') aren't supported even though they - # are perfectly legitimate locales: - # https://github.com/mitsuhiko/babel/issues/37 - # In Babel 1.3 they fixed the bug and they support these locales, but - # they are still not explicitly "listed" by locale_identifiers(). - # That is why we add the locales here explicitly if necessary so that - # they are listed as supported. - aliases = {'zh': 'zh_CN', - 'zh_Hant_HK': 'zh_HK', - 'zh_Hant': 'zh_TW', - 'fil': 'tl_PH'} - for (locale, alias) in six.iteritems(aliases): - if locale in language_list and alias not in language_list: - language_list.append(alias) - - _AVAILABLE_LANGUAGES[domain] = language_list - return copy.copy(language_list) - - -def translate(obj, desired_locale=None): - """Gets the translated unicode representation of the given object. - - If the object is not translatable it is returned as-is. - If the locale is None the object is translated to the system locale. - - :param obj: the object to translate - :param desired_locale: the locale to translate the message to, if None the - default system locale will be used - :returns: the translated object in unicode, or the original object if - it could not be translated - """ - message = obj - if not isinstance(message, Message): - # If the object to translate is not already translatable, - # let's first get its unicode representation - message = six.text_type(obj) - if isinstance(message, Message): - # Even after unicoding() we still need to check if we are - # running with translatable unicode before translating - return message.translate(desired_locale) - return obj - - -def _translate_args(args, desired_locale=None): - """Translates all the translatable elements of the given arguments object. - - This method is used for translating the translatable values in method - arguments which include values of tuples or dictionaries. - If the object is not a tuple or a dictionary the object itself is - translated if it is translatable. - - If the locale is None the object is translated to the system locale. - - :param args: the args to translate - :param desired_locale: the locale to translate the args to, if None the - default system locale will be used - :returns: a new args object with the translated contents of the original - """ - if isinstance(args, tuple): - return tuple(translate(v, desired_locale) for v in args) - if isinstance(args, dict): - translated_dict = {} - for (k, v) in six.iteritems(args): - translated_v = translate(v, desired_locale) - translated_dict[k] = translated_v - return translated_dict - return translate(args, desired_locale) - - -class TranslationHandler(handlers.MemoryHandler): - """Handler that translates records before logging them. - - The TranslationHandler takes a locale and a target logging.Handler object - to forward LogRecord objects to after translating them. This handler - depends on Message objects being logged, instead of regular strings. - - The handler can be configured declaratively in the logging.conf as follows: - - [handlers] - keys = translatedlog, translator - - [handler_translatedlog] - class = handlers.WatchedFileHandler - args = ('/var/log/api-localized.log',) - formatter = context - - [handler_translator] - class = openstack.common.log.TranslationHandler - target = translatedlog - args = ('zh_CN',) - - If the specified locale is not available in the system, the handler will - log in the default locale. - """ - - def __init__(self, locale=None, target=None): - """Initialize a TranslationHandler - - :param locale: locale to use for translating messages - :param target: logging.Handler object to forward - LogRecord objects to after translation - """ - # NOTE(luisg): In order to allow this handler to be a wrapper for - # other handlers, such as a FileHandler, and still be able to - # configure it using logging.conf, this handler has to extend - # MemoryHandler because only the MemoryHandlers' logging.conf - # parsing is implemented such that it accepts a target handler. - handlers.MemoryHandler.__init__(self, capacity=0, target=target) - self.locale = locale - - def setFormatter(self, fmt): - self.target.setFormatter(fmt) - - def emit(self, record): - # We save the message from the original record to restore it - # after translation, so other handlers are not affected by this - original_msg = record.msg - original_args = record.args - - try: - self._translate_and_log_record(record) - finally: - record.msg = original_msg - record.args = original_args - - def _translate_and_log_record(self, record): - record.msg = translate(record.msg, self.locale) - - # In addition to translating the message, we also need to translate - # arguments that were passed to the log method that were not part - # of the main message e.g., log.info(_('Some message %s'), this_one)) - record.args = _translate_args(record.args, self.locale) - - self.target.emit(record) diff --git a/murano/openstack/common/log.py b/murano/openstack/common/log.py index 95693906b..b668c2e02 100644 --- a/murano/openstack/common/log.py +++ b/murano/openstack/common/log.py @@ -46,7 +46,7 @@ from six import moves _PY26 = sys.version_info[0:2] == (2, 6) -from murano.openstack.common._i18n import _ +from murano.openstack.common._i18n import _, _LI from murano.openstack.common import local @@ -521,8 +521,9 @@ def _setup_logging_from_conf(project, version): if CONF.log_format: handler.setFormatter(logging.Formatter(fmt=CONF.log_format, datefmt=datefmt)) - log_root.info('Deprecated: log_format is now deprecated and will ' - 'be removed in the next release') + log_root.info(_LI( + 'Deprecated: log_format is now deprecated and will ' + 'be removed in the next release')) else: handler.setFormatter(ContextFormatter(project=project, version=version, diff --git a/murano/openstack/common/processutils.py b/murano/openstack/common/processutils.py index 2294f34df..9e9b1b02a 100644 --- a/murano/openstack/common/processutils.py +++ b/murano/openstack/common/processutils.py @@ -189,7 +189,7 @@ def execute(*cmd, **kwargs): break obj.stdin.close() # pylint: disable=E1101 _returncode = obj.returncode # pylint: disable=E1101 - LOG.log(loglevel, 'Result was %s' % _returncode) + LOG.log(loglevel, _('Result was %s'), _returncode) if not ignore_exit_code and _returncode not in check_exit_code: (stdout, stderr) = result sanitized_stdout = strutils.mask_password(stdout) diff --git a/murano/policy/model_policy_enforcer.py b/murano/policy/model_policy_enforcer.py index 180eac47d..5eed8c093 100644 --- a/murano/policy/model_policy_enforcer.py +++ b/murano/policy/model_policy_enforcer.py @@ -15,7 +15,7 @@ import re -from murano.openstack.common.gettextutils import _ +from murano.common.i18n import _, _LI from murano.openstack.common import log as logging from murano.policy import congress_rules @@ -60,7 +60,7 @@ class ModelPolicyEnforcer(object): if not client: raise ValueError(_('Congress client is not configured!')) - LOG.info('Validating model') + LOG.info(_LI('Validating model')) LOG.debug(model) rules = congress_rules.CongressRulesManager().convert( @@ -87,11 +87,12 @@ class ModelPolicyEnforcer(object): if messages: result_str = "\n ".join(map(str, messages)) - raise ValidationError( - _("Murano object model validation failed:") + + msg = _("Murano object model validation failed: {0}").format( "\n " + result_str) + LOG.error(msg) + raise ValidationError(msg) else: - LOG.info('Model valid') + LOG.info(_LI('Model valid')) def _parse_messages(self, env_id, results): """Transforms list of strings in format @@ -110,4 +111,4 @@ class ModelPolicyEnforcer(object): if env_id in match.group(1): messages.append(match.group(3)) - return messages \ No newline at end of file + return messages diff --git a/murano/tests/unit/db/migration/test_migrations_base.py b/murano/tests/unit/db/migration/test_migrations_base.py index cf171d4ad..08164f9fa 100644 --- a/murano/tests/unit/db/migration/test_migrations_base.py +++ b/murano/tests/unit/db/migration/test_migrations_base.py @@ -31,6 +31,7 @@ from alembic import migration from alembic import script as alembic_script from oslo.config import cfg +from murano.common.i18n import _LE import murano.db.migration from murano.openstack.common import log as logging @@ -178,6 +179,7 @@ class BaseWalkMigrationTestCase(object): if check: check(engine, data) except Exception: - LOG.error("Failed to migrate to version %s on engine %s" % - (version, engine)) + LOG.error(_LE( + "Failed to migrate to version %(ver)s on engine %(eng)s") % + {'ver': version, 'eng': engine}) raise diff --git a/murano/utils.py b/murano/utils.py index c23bb3135..5e88b7336 100644 --- a/murano/utils.py +++ b/murano/utils.py @@ -16,10 +16,10 @@ import functools from webob import exc +from murano.common.i18n import _LI from murano.db import models from murano.db.services import sessions from murano.db import session as db_session -from murano.openstack.common.gettextutils import _ from murano.openstack.common import log as logging from murano.services import states @@ -32,14 +32,14 @@ def verify_env(func): unit = db_session.get_session() environment = unit.query(models.Environment).get(environment_id) if environment is None: - LOG.info(_("Environment with id '{0}'" - " not found").format(environment_id)) + LOG.info(_LI("Environment with id '{0}'" + " not found").format(environment_id)) raise exc.HTTPNotFound() if hasattr(request, 'context'): if environment.tenant_id != request.context.tenant: - LOG.info(_('User is not authorized to access' - ' this tenant resources')) + LOG.info(_LI('User is not authorized to access' + ' these tenant resources')) raise exc.HTTPUnauthorized() return func(self, request, environment_id, *args, **kwargs) @@ -50,7 +50,7 @@ def verify_session(func): @functools.wraps(func) def __inner(self, request, *args, **kwargs): if hasattr(request, 'context') and not request.context.session: - LOG.info(_('Session is required for this call')) + LOG.info(_LI('Session is required for this call')) raise exc.HTTPForbidden() session_id = request.context.session @@ -59,18 +59,18 @@ def verify_session(func): session = unit.query(models.Session).get(session_id) if session is None: - LOG.info(_('Session ' - 'is not found').format(session_id)) + LOG.info(_LI('Session ' + 'is not found').format(session_id)) raise exc.HTTPForbidden() if not sessions.SessionServices.validate(session): - LOG.info(_('Session ' - 'is invalid').format(session_id)) + LOG.info(_LI('Session ' + 'is invalid').format(session_id)) raise exc.HTTPForbidden() if session.state == states.SessionState.DEPLOYING: - LOG.info(_('Session is already in ' - 'deployment state').format(session_id)) + LOG.info(_LI('Session is already in ' + 'deployment state').format(session_id)) raise exc.HTTPForbidden() return func(self, request, *args, **kwargs) return __inner diff --git a/openstack-common.conf b/openstack-common.conf index 12c0c8d97..28868605e 100644 --- a/openstack-common.conf +++ b/openstack-common.conf @@ -2,7 +2,6 @@ # The list of modules to copy from openstack-common module=exception -module=gettextutils module=lockutils module=log module=policy diff --git a/requirements.txt b/requirements.txt index 0a8a6e7a4..66568e2bb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -33,6 +33,7 @@ oslo.config>=1.4.0 # Apache-2.0 oslo.messaging>=1.4.0,!=1.5.0 oslo.serialization>=1.0.0 # Apache-2.0 oslo.utils>=1.1.0 # Apache-2.0 +oslo.i18n>=1.3.0 # not listed in global requirements yaql>=0.2.3,<0.3 diff --git a/tox.ini b/tox.ini index 51704d081..51647d7dd 100644 --- a/tox.ini +++ b/tox.ini @@ -48,5 +48,5 @@ builtins = _ exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,tools [hacking] -import_exceptions = murano.openstack.common.gettextutils, - oslo.db.sqlalchemy.test_base +import_exceptions = oslo.db.sqlalchemy.test_base, + murano.common.i18n