Merge "Merge from oslo-incubator"
This commit is contained in:
commit
6aca4edc70
|
@ -23,7 +23,6 @@ Usual usage in an openstack.common module:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
import functools
|
|
||||||
import gettext
|
import gettext
|
||||||
import locale
|
import locale
|
||||||
from logging import handlers
|
from logging import handlers
|
||||||
|
@ -42,7 +41,7 @@ class TranslatorFactory(object):
|
||||||
"""Create translator functions
|
"""Create translator functions
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, domain, lazy=False, localedir=None):
|
def __init__(self, domain, localedir=None):
|
||||||
"""Establish a set of translation functions for the domain.
|
"""Establish a set of translation functions for the domain.
|
||||||
|
|
||||||
:param domain: Name of translation domain,
|
:param domain: Name of translation domain,
|
||||||
|
@ -55,7 +54,6 @@ class TranslatorFactory(object):
|
||||||
:type localedir: str
|
:type localedir: str
|
||||||
"""
|
"""
|
||||||
self.domain = domain
|
self.domain = domain
|
||||||
self.lazy = lazy
|
|
||||||
if localedir is None:
|
if localedir is None:
|
||||||
localedir = os.environ.get(domain.upper() + '_LOCALEDIR')
|
localedir = os.environ.get(domain.upper() + '_LOCALEDIR')
|
||||||
self.localedir = localedir
|
self.localedir = localedir
|
||||||
|
@ -75,16 +73,19 @@ class TranslatorFactory(object):
|
||||||
"""
|
"""
|
||||||
if domain is None:
|
if domain is None:
|
||||||
domain = self.domain
|
domain = self.domain
|
||||||
if self.lazy:
|
t = gettext.translation(domain,
|
||||||
return functools.partial(Message, domain=domain)
|
localedir=self.localedir,
|
||||||
t = gettext.translation(
|
fallback=True)
|
||||||
domain,
|
# Use the appropriate method of the translation object based
|
||||||
localedir=self.localedir,
|
# on the python version.
|
||||||
fallback=True,
|
m = t.gettext if six.PY3 else t.ugettext
|
||||||
)
|
|
||||||
if six.PY3:
|
def f(msg):
|
||||||
return t.gettext
|
"""oslo.i18n.gettextutils translation function."""
|
||||||
return t.ugettext
|
if USE_LAZY:
|
||||||
|
return Message(msg, domain=domain)
|
||||||
|
return m(msg)
|
||||||
|
return f
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def primary(self):
|
def primary(self):
|
||||||
|
@ -147,19 +148,11 @@ def enable_lazy():
|
||||||
your project is importing _ directly instead of using the
|
your project is importing _ directly instead of using the
|
||||||
gettextutils.install() way of importing the _ function.
|
gettextutils.install() way of importing the _ function.
|
||||||
"""
|
"""
|
||||||
# FIXME(dhellmann): This function will be removed in oslo.i18n,
|
global USE_LAZY
|
||||||
# because the TranslatorFactory makes it superfluous.
|
|
||||||
global _, _LI, _LW, _LE, _LC, USE_LAZY
|
|
||||||
tf = TranslatorFactory('trove', lazy=True)
|
|
||||||
_ = tf.primary
|
|
||||||
_LI = tf.log_info
|
|
||||||
_LW = tf.log_warning
|
|
||||||
_LE = tf.log_error
|
|
||||||
_LC = tf.log_critical
|
|
||||||
USE_LAZY = True
|
USE_LAZY = True
|
||||||
|
|
||||||
|
|
||||||
def install(domain, lazy=False):
|
def install(domain):
|
||||||
"""Install a _() function using the given translation domain.
|
"""Install a _() function using the given translation domain.
|
||||||
|
|
||||||
Given a translation domain, install a _() function using gettext's
|
Given a translation domain, install a _() function using gettext's
|
||||||
|
@ -170,26 +163,14 @@ def install(domain, lazy=False):
|
||||||
a translation-domain-specific environment variable (e.g.
|
a translation-domain-specific environment variable (e.g.
|
||||||
NOVA_LOCALEDIR).
|
NOVA_LOCALEDIR).
|
||||||
|
|
||||||
|
Note that to enable lazy translation, enable_lazy must be
|
||||||
|
called.
|
||||||
|
|
||||||
:param domain: the translation domain
|
: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
|
||||||
from six import moves
|
tf = TranslatorFactory(domain)
|
||||||
tf = TranslatorFactory(domain, lazy=True)
|
moves.builtins.__dict__['_'] = tf.primary
|
||||||
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):
|
class Message(six.text_type):
|
||||||
|
|
|
@ -168,6 +168,10 @@ def dumps(value, default=to_primitive, **kwargs):
|
||||||
return json.dumps(value, default=default, **kwargs)
|
return json.dumps(value, default=default, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def dump(obj, fp, *args, **kwargs):
|
||||||
|
return json.dump(obj, fp, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def loads(s, encoding='utf-8', **kwargs):
|
def loads(s, encoding='utf-8', **kwargs):
|
||||||
return json.loads(strutils.safe_decode(s, encoding), **kwargs)
|
return json.loads(strutils.safe_decode(s, encoding), **kwargs)
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,6 @@ import logging
|
||||||
import logging.config
|
import logging.config
|
||||||
import logging.handlers
|
import logging.handlers
|
||||||
import os
|
import os
|
||||||
import re
|
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
|
@ -41,34 +40,19 @@ from oslo.config import cfg
|
||||||
import six
|
import six
|
||||||
from six import moves
|
from six import moves
|
||||||
|
|
||||||
|
_PY26 = sys.version_info[0:2] == (2, 6)
|
||||||
|
|
||||||
from trove.openstack.common.gettextutils import _
|
from trove.openstack.common.gettextutils import _
|
||||||
from trove.openstack.common import importutils
|
from trove.openstack.common import importutils
|
||||||
from trove.openstack.common import jsonutils
|
from trove.openstack.common import jsonutils
|
||||||
from trove.openstack.common import local
|
from trove.openstack.common import local
|
||||||
|
# NOTE(flaper87): Pls, remove when graduating this module
|
||||||
|
# from the incubator.
|
||||||
|
from trove.openstack.common.strutils import mask_password # noqa
|
||||||
|
|
||||||
|
|
||||||
_DEFAULT_LOG_DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
|
_DEFAULT_LOG_DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
|
||||||
|
|
||||||
_SANITIZE_KEYS = ['adminPass', 'admin_pass', 'password', 'admin_password']
|
|
||||||
|
|
||||||
# NOTE(ldbragst): Let's build a list of regex objects using the list of
|
|
||||||
# _SANITIZE_KEYS we already have. This way, we only have to add the new key
|
|
||||||
# to the list of _SANITIZE_KEYS and we can generate regular expressions
|
|
||||||
# for XML and JSON automatically.
|
|
||||||
_SANITIZE_PATTERNS = []
|
|
||||||
_FORMAT_PATTERNS = [r'(%(key)s\s*[=]\s*[\"\']).*?([\"\'])',
|
|
||||||
r'(<%(key)s>).*?(</%(key)s>)',
|
|
||||||
r'([\"\']%(key)s[\"\']\s*:\s*[\"\']).*?([\"\'])',
|
|
||||||
r'([\'"].*?%(key)s[\'"]\s*:\s*u?[\'"]).*?([\'"])',
|
|
||||||
r'([\'"].*?%(key)s[\'"]\s*,\s*\'--?[A-z]+\'\s*,\s*u?[\'"])'
|
|
||||||
'.*?([\'"])',
|
|
||||||
r'(%(key)s\s*--?[A-z]+\s*).*?([\s])']
|
|
||||||
|
|
||||||
for key in _SANITIZE_KEYS:
|
|
||||||
for pattern in _FORMAT_PATTERNS:
|
|
||||||
reg_ex = re.compile(pattern % {'key': key}, re.DOTALL)
|
|
||||||
_SANITIZE_PATTERNS.append(reg_ex)
|
|
||||||
|
|
||||||
|
|
||||||
common_cli_opts = [
|
common_cli_opts = [
|
||||||
cfg.BoolOpt('debug',
|
cfg.BoolOpt('debug',
|
||||||
|
@ -138,6 +122,12 @@ generic_log_opts = [
|
||||||
help='Log output to standard error.')
|
help='Log output to standard error.')
|
||||||
]
|
]
|
||||||
|
|
||||||
|
DEFAULT_LOG_LEVELS = ['amqp=WARN', 'amqplib=WARN', 'boto=WARN',
|
||||||
|
'qpid=WARN', 'sqlalchemy=WARN', 'suds=INFO',
|
||||||
|
'oslo.messaging=INFO', 'iso8601=WARN',
|
||||||
|
'requests.packages.urllib3.connectionpool=WARN',
|
||||||
|
'urllib3.connectionpool=WARN', 'websocket=WARN']
|
||||||
|
|
||||||
log_opts = [
|
log_opts = [
|
||||||
cfg.StrOpt('logging_context_format_string',
|
cfg.StrOpt('logging_context_format_string',
|
||||||
default='%(asctime)s.%(msecs)03d %(process)d %(levelname)s '
|
default='%(asctime)s.%(msecs)03d %(process)d %(levelname)s '
|
||||||
|
@ -156,17 +146,7 @@ log_opts = [
|
||||||
'%(instance)s',
|
'%(instance)s',
|
||||||
help='Prefix each line of exception output with this format.'),
|
help='Prefix each line of exception output with this format.'),
|
||||||
cfg.ListOpt('default_log_levels',
|
cfg.ListOpt('default_log_levels',
|
||||||
default=[
|
default=DEFAULT_LOG_LEVELS,
|
||||||
'amqp=WARN',
|
|
||||||
'amqplib=WARN',
|
|
||||||
'boto=WARN',
|
|
||||||
'qpid=WARN',
|
|
||||||
'sqlalchemy=WARN',
|
|
||||||
'suds=INFO',
|
|
||||||
'oslo.messaging=INFO',
|
|
||||||
'iso8601=WARN',
|
|
||||||
'requests.packages.urllib3.connectionpool=WARN'
|
|
||||||
],
|
|
||||||
help='List of logger=LEVEL pairs.'),
|
help='List of logger=LEVEL pairs.'),
|
||||||
cfg.BoolOpt('publish_errors',
|
cfg.BoolOpt('publish_errors',
|
||||||
default=False,
|
default=False,
|
||||||
|
@ -181,11 +161,11 @@ log_opts = [
|
||||||
cfg.StrOpt('instance_format',
|
cfg.StrOpt('instance_format',
|
||||||
default='[instance: %(uuid)s] ',
|
default='[instance: %(uuid)s] ',
|
||||||
help='The format for an instance that is passed with the log '
|
help='The format for an instance that is passed with the log '
|
||||||
'message. '),
|
'message.'),
|
||||||
cfg.StrOpt('instance_uuid_format',
|
cfg.StrOpt('instance_uuid_format',
|
||||||
default='[instance: %(uuid)s] ',
|
default='[instance: %(uuid)s] ',
|
||||||
help='The format for an instance UUID that is passed with the '
|
help='The format for an instance UUID that is passed with the '
|
||||||
'log message. '),
|
'log message.'),
|
||||||
]
|
]
|
||||||
|
|
||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
|
@ -244,45 +224,20 @@ def _get_log_file_path(binary=None):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def mask_password(message, secret="***"):
|
|
||||||
"""Replace password with 'secret' in message.
|
|
||||||
|
|
||||||
:param message: The string which includes security information.
|
|
||||||
:param secret: value with which to replace passwords.
|
|
||||||
:returns: The unicode value of message with the password fields masked.
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
>>> mask_password("'adminPass' : 'aaaaa'")
|
|
||||||
"'adminPass' : '***'"
|
|
||||||
>>> mask_password("'admin_pass' : 'aaaaa'")
|
|
||||||
"'admin_pass' : '***'"
|
|
||||||
>>> mask_password('"password" : "aaaaa"')
|
|
||||||
'"password" : "***"'
|
|
||||||
>>> mask_password("'original_password' : 'aaaaa'")
|
|
||||||
"'original_password' : '***'"
|
|
||||||
>>> mask_password("u'original_password' : u'aaaaa'")
|
|
||||||
"u'original_password' : u'***'"
|
|
||||||
"""
|
|
||||||
message = six.text_type(message)
|
|
||||||
|
|
||||||
# NOTE(ldbragst): Check to see if anything in message contains any key
|
|
||||||
# specified in _SANITIZE_KEYS, if not then just return the message since
|
|
||||||
# we don't have to mask any passwords.
|
|
||||||
if not any(key in message for key in _SANITIZE_KEYS):
|
|
||||||
return message
|
|
||||||
|
|
||||||
secret = r'\g<1>' + secret + r'\g<2>'
|
|
||||||
for pattern in _SANITIZE_PATTERNS:
|
|
||||||
message = re.sub(pattern, secret, message)
|
|
||||||
return message
|
|
||||||
|
|
||||||
|
|
||||||
class BaseLoggerAdapter(logging.LoggerAdapter):
|
class BaseLoggerAdapter(logging.LoggerAdapter):
|
||||||
|
|
||||||
def audit(self, msg, *args, **kwargs):
|
def audit(self, msg, *args, **kwargs):
|
||||||
self.log(logging.AUDIT, msg, *args, **kwargs)
|
self.log(logging.AUDIT, msg, *args, **kwargs)
|
||||||
|
|
||||||
|
def isEnabledFor(self, level):
|
||||||
|
if _PY26:
|
||||||
|
# This method was added in python 2.7 (and it does the exact
|
||||||
|
# same logic, so we need to do the exact same logic so that
|
||||||
|
# python 2.6 has this capability as well).
|
||||||
|
return self.logger.isEnabledFor(level)
|
||||||
|
else:
|
||||||
|
return super(BaseLoggerAdapter, self).isEnabledFor(level)
|
||||||
|
|
||||||
|
|
||||||
class LazyAdapter(BaseLoggerAdapter):
|
class LazyAdapter(BaseLoggerAdapter):
|
||||||
def __init__(self, name='unknown', version='unknown'):
|
def __init__(self, name='unknown', version='unknown'):
|
||||||
|
@ -295,6 +250,11 @@ class LazyAdapter(BaseLoggerAdapter):
|
||||||
def logger(self):
|
def logger(self):
|
||||||
if not self._logger:
|
if not self._logger:
|
||||||
self._logger = getLogger(self.name, self.version)
|
self._logger = getLogger(self.name, self.version)
|
||||||
|
if six.PY3:
|
||||||
|
# In Python 3, the code fails because the 'manager' attribute
|
||||||
|
# cannot be found when using a LoggerAdapter as the
|
||||||
|
# underlying logger. Work around this issue.
|
||||||
|
self._logger.manager = self._logger.logger.manager
|
||||||
return self._logger
|
return self._logger
|
||||||
|
|
||||||
|
|
||||||
|
@ -448,7 +408,7 @@ def _load_log_config(log_config_append):
|
||||||
try:
|
try:
|
||||||
logging.config.fileConfig(log_config_append,
|
logging.config.fileConfig(log_config_append,
|
||||||
disable_existing_loggers=False)
|
disable_existing_loggers=False)
|
||||||
except moves.configparser.Error as exc:
|
except (moves.configparser.Error, KeyError) as exc:
|
||||||
raise LogConfigError(log_config_append, six.text_type(exc))
|
raise LogConfigError(log_config_append, six.text_type(exc))
|
||||||
|
|
||||||
|
|
||||||
|
@ -461,9 +421,20 @@ def setup(product_name, version='unknown'):
|
||||||
sys.excepthook = _create_logging_excepthook(product_name)
|
sys.excepthook = _create_logging_excepthook(product_name)
|
||||||
|
|
||||||
|
|
||||||
def set_defaults(logging_context_format_string):
|
def set_defaults(logging_context_format_string=None,
|
||||||
cfg.set_defaults(
|
default_log_levels=None):
|
||||||
log_opts, logging_context_format_string=logging_context_format_string)
|
# Just in case the caller is not setting the
|
||||||
|
# default_log_level. This is insurance because
|
||||||
|
# we introduced the default_log_level parameter
|
||||||
|
# later in a backwards in-compatible change
|
||||||
|
if default_log_levels is not None:
|
||||||
|
cfg.set_defaults(
|
||||||
|
log_opts,
|
||||||
|
default_log_levels=default_log_levels)
|
||||||
|
if logging_context_format_string is not None:
|
||||||
|
cfg.set_defaults(
|
||||||
|
log_opts,
|
||||||
|
logging_context_format_string=logging_context_format_string)
|
||||||
|
|
||||||
|
|
||||||
def _find_facility_from_conf():
|
def _find_facility_from_conf():
|
||||||
|
|
|
@ -18,7 +18,7 @@ System-level utilities and helper functions.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import errno
|
import errno
|
||||||
import logging as stdlib_logging
|
import logging
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
|
@ -30,7 +30,7 @@ from eventlet import greenthread
|
||||||
import six
|
import six
|
||||||
|
|
||||||
from trove.openstack.common.gettextutils import _
|
from trove.openstack.common.gettextutils import _
|
||||||
from trove.openstack.common import log as logging
|
from trove.openstack.common import strutils
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
@ -115,8 +115,7 @@ def execute(*cmd, **kwargs):
|
||||||
execute this command. Defaults to false.
|
execute this command. Defaults to false.
|
||||||
:type shell: boolean
|
:type shell: boolean
|
||||||
:param loglevel: log level for execute commands.
|
:param loglevel: log level for execute commands.
|
||||||
:type loglevel: int. (Should be stdlib_logging.DEBUG or
|
:type loglevel: int. (Should be logging.DEBUG or logging.INFO)
|
||||||
stdlib_logging.INFO)
|
|
||||||
:returns: (stdout, stderr) from process execution
|
:returns: (stdout, stderr) from process execution
|
||||||
:raises: :class:`UnknownArgumentError` on
|
:raises: :class:`UnknownArgumentError` on
|
||||||
receiving unknown arguments
|
receiving unknown arguments
|
||||||
|
@ -132,7 +131,7 @@ def execute(*cmd, **kwargs):
|
||||||
run_as_root = kwargs.pop('run_as_root', False)
|
run_as_root = kwargs.pop('run_as_root', False)
|
||||||
root_helper = kwargs.pop('root_helper', '')
|
root_helper = kwargs.pop('root_helper', '')
|
||||||
shell = kwargs.pop('shell', False)
|
shell = kwargs.pop('shell', False)
|
||||||
loglevel = kwargs.pop('loglevel', stdlib_logging.DEBUG)
|
loglevel = kwargs.pop('loglevel', logging.DEBUG)
|
||||||
|
|
||||||
if isinstance(check_exit_code, bool):
|
if isinstance(check_exit_code, bool):
|
||||||
ignore_exit_code = not check_exit_code
|
ignore_exit_code = not check_exit_code
|
||||||
|
@ -141,8 +140,7 @@ def execute(*cmd, **kwargs):
|
||||||
check_exit_code = [check_exit_code]
|
check_exit_code = [check_exit_code]
|
||||||
|
|
||||||
if kwargs:
|
if kwargs:
|
||||||
raise UnknownArgumentError(_('Got unknown keyword args '
|
raise UnknownArgumentError(_('Got unknown keyword args: %r') % kwargs)
|
||||||
'to utils.execute: %r') % kwargs)
|
|
||||||
|
|
||||||
if run_as_root and hasattr(os, 'geteuid') and os.geteuid() != 0:
|
if run_as_root and hasattr(os, 'geteuid') and os.geteuid() != 0:
|
||||||
if not root_helper:
|
if not root_helper:
|
||||||
|
@ -157,7 +155,7 @@ def execute(*cmd, **kwargs):
|
||||||
attempts -= 1
|
attempts -= 1
|
||||||
try:
|
try:
|
||||||
LOG.log(loglevel, 'Running cmd (subprocess): %s',
|
LOG.log(loglevel, 'Running cmd (subprocess): %s',
|
||||||
' '.join(logging.mask_password(cmd)))
|
strutils.mask_password(' '.join(cmd)))
|
||||||
_PIPE = subprocess.PIPE # pylint: disable=E1101
|
_PIPE = subprocess.PIPE # pylint: disable=E1101
|
||||||
|
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
|
|
|
@ -50,6 +50,28 @@ SLUGIFY_STRIP_RE = re.compile(r"[^\w\s-]")
|
||||||
SLUGIFY_HYPHENATE_RE = re.compile(r"[-\s]+")
|
SLUGIFY_HYPHENATE_RE = re.compile(r"[-\s]+")
|
||||||
|
|
||||||
|
|
||||||
|
# NOTE(flaper87): The following 3 globals are used by `mask_password`
|
||||||
|
_SANITIZE_KEYS = ['adminPass', 'admin_pass', 'password', 'admin_password']
|
||||||
|
|
||||||
|
# NOTE(ldbragst): Let's build a list of regex objects using the list of
|
||||||
|
# _SANITIZE_KEYS we already have. This way, we only have to add the new key
|
||||||
|
# to the list of _SANITIZE_KEYS and we can generate regular expressions
|
||||||
|
# for XML and JSON automatically.
|
||||||
|
_SANITIZE_PATTERNS = []
|
||||||
|
_FORMAT_PATTERNS = [r'(%(key)s\s*[=]\s*[\"\']).*?([\"\'])',
|
||||||
|
r'(<%(key)s>).*?(</%(key)s>)',
|
||||||
|
r'([\"\']%(key)s[\"\']\s*:\s*[\"\']).*?([\"\'])',
|
||||||
|
r'([\'"].*?%(key)s[\'"]\s*:\s*u?[\'"]).*?([\'"])',
|
||||||
|
r'([\'"].*?%(key)s[\'"]\s*,\s*\'--?[A-z]+\'\s*,\s*u?[\'"])'
|
||||||
|
'.*?([\'"])',
|
||||||
|
r'(%(key)s\s*--?[A-z]+\s*)\S+(\s*)']
|
||||||
|
|
||||||
|
for key in _SANITIZE_KEYS:
|
||||||
|
for pattern in _FORMAT_PATTERNS:
|
||||||
|
reg_ex = re.compile(pattern % {'key': key}, re.DOTALL)
|
||||||
|
_SANITIZE_PATTERNS.append(reg_ex)
|
||||||
|
|
||||||
|
|
||||||
def int_from_bool_as_string(subject):
|
def int_from_bool_as_string(subject):
|
||||||
"""Interpret a string as a boolean and return either 1 or 0.
|
"""Interpret a string as a boolean and return either 1 or 0.
|
||||||
|
|
||||||
|
@ -237,3 +259,37 @@ def to_slug(value, incoming=None, errors="strict"):
|
||||||
"ascii", "ignore").decode("ascii")
|
"ascii", "ignore").decode("ascii")
|
||||||
value = SLUGIFY_STRIP_RE.sub("", value).strip().lower()
|
value = SLUGIFY_STRIP_RE.sub("", value).strip().lower()
|
||||||
return SLUGIFY_HYPHENATE_RE.sub("-", value)
|
return SLUGIFY_HYPHENATE_RE.sub("-", value)
|
||||||
|
|
||||||
|
|
||||||
|
def mask_password(message, secret="***"):
|
||||||
|
"""Replace password with 'secret' in message.
|
||||||
|
|
||||||
|
:param message: The string which includes security information.
|
||||||
|
:param secret: value with which to replace passwords.
|
||||||
|
:returns: The unicode value of message with the password fields masked.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
>>> mask_password("'adminPass' : 'aaaaa'")
|
||||||
|
"'adminPass' : '***'"
|
||||||
|
>>> mask_password("'admin_pass' : 'aaaaa'")
|
||||||
|
"'admin_pass' : '***'"
|
||||||
|
>>> mask_password('"password" : "aaaaa"')
|
||||||
|
'"password" : "***"'
|
||||||
|
>>> mask_password("'original_password' : 'aaaaa'")
|
||||||
|
"'original_password' : '***'"
|
||||||
|
>>> mask_password("u'original_password' : u'aaaaa'")
|
||||||
|
"u'original_password' : u'***'"
|
||||||
|
"""
|
||||||
|
message = six.text_type(message)
|
||||||
|
|
||||||
|
# NOTE(ldbragst): Check to see if anything in message contains any key
|
||||||
|
# specified in _SANITIZE_KEYS, if not then just return the message since
|
||||||
|
# we don't have to mask any passwords.
|
||||||
|
if not any(key in message for key in _SANITIZE_KEYS):
|
||||||
|
return message
|
||||||
|
|
||||||
|
secret = r'\g<1>' + secret + r'\g<2>'
|
||||||
|
for pattern in _SANITIZE_PATTERNS:
|
||||||
|
message = re.sub(pattern, secret, message)
|
||||||
|
return message
|
||||||
|
|
Loading…
Reference in New Issue