resync oslo-incubator code
This commit syncs the following oslo incubator modules used by Trove
and all dependent changes.
__init__.py
6b048e79 Let oslotest manage the six.move setting for mox
context.py
411ba356 Simplify is_user_context method
9b73877b Add a RequestContext.from_dict method
85d1ce6e Python 3: enable tests/unit/middleware/test_request_id.py
c0d357bb Add model_query() to db.sqlalchemy.utils module
eventlet_backdoor.py
a3220c51 add list_opts to all modules with configuration options
5d40e143 Remove code that moved to oslo.i18n
90ae24bf Remove redundant default=None for config options
fcf517d7 Update oslo log messages with translation domains
ad17a697 Fix filter() usage due to python 3 compability
8b2b0b74 Use hacking import_exceptions for gettextutils._
12bcdb71 Remove vim header
log.py
943cb94a Merge "Make use_syslog=True log to syslog via /dev/log"
8345204c Merge "add list_opts to all modules with configuration options"
ac4330dd Make use_syslog=True log to syslog via /dev/log
df774ff4
Import PublishErrorsHandler from oslo.messaging
a3220c51 add list_opts to all modules with configuration options
6c706c5c Delete graduated serialization files
5d40e143 Remove code that moved to oslo.i18n
6ff6b4b4 Switch oslo-incubator to use oslo.utils and remove old modules
aa744115 log: add missing space in error message
037dee00 Set stevedore log level to WARN by default
759bd879 Merge "Set keystonemiddleware and routes.middleware to log on WARN level"
71d072f1 Merge "Except socket.error if syslog isn't running"
37c00918 Add unicode coercion of logged messages to ContextFormatter
66144135 Correct coercion of logged message to unicode
loopingcall.py
5d40e143 Remove code that moved to oslo.i18n
e3773930 Changes calcuation of variable delay
ab5d5f1c Use timestamp in loopingcall
bc48099a Log the function name of looping call
fb4e863c Remove deprecated LoopingCall
fcf517d7 Update oslo log messages with translation domains
8b2b0b74 Use hacking import_exceptions for gettextutils._
12bcdb71 Remove vim header
service.py
5d40e143 Remove code that moved to oslo.i18n
6ede600f rpc, notifier: remove deprecated modules
threadgroup.py
1523f000 threadgroup: don't log GreenletExit
5a1a0166 Make stop_timers() method public
fdc88831 Add graceful stop function to ThreadGroup.stop
5f8ace05 Merge "threadgroup: use threading rather than greenthread"
2d06d6ca Simple typo correction
4d18b57a threadgroup: use threading rather than greenthread
25ff65e9 Make wait & stop methods work on all threads
12bcdb71 Remove vim header
9d3c34b5 Add a link method to Thread
versionutils.py
5d40e143 Remove code that moved to oslo.i18n
1c3ecfcd Enhance versionutils.deprecated to work with classes
7d42c107 Merge "Add Kilo release name to versionutils"
9a462718 Add Kilo release name to versionutils
a2ad3a25 Allow deprecated decorator to specify no plan for removal
05ae498b Add JUNO as a target to versionutils module
de4adbc4 pep8: fixed multiple violations
Closes-Bug: #1366189
Change-Id: I2289452a9b838e22bb6d4dd1a854fbeb326042d2
This commit is contained in:
parent
4d31433b1e
commit
6ea94c4bf7
|
@ -17,6 +17,8 @@ import re
|
|||
import webob.exc
|
||||
import wsgi
|
||||
|
||||
from oslo.utils import strutils
|
||||
|
||||
from trove.common import exception
|
||||
from trove.openstack.common import log as logging
|
||||
from trove.common.i18n import _
|
||||
|
@ -59,7 +61,7 @@ class TenantBasedAuth(object):
|
|||
match_for_tenant = self.tenant_scoped_url.match(request.path_info)
|
||||
if (match_for_tenant and
|
||||
tenant_id == match_for_tenant.group('tenant_id')):
|
||||
LOG.debug(logging.mask_password(
|
||||
LOG.debug(strutils.mask_password(
|
||||
_("Authorized tenant '%(tenant_id)s' request: "
|
||||
"%(request)s") %
|
||||
{'tenant_id': tenant_id, 'request': request}))
|
||||
|
|
|
@ -191,7 +191,11 @@ def poll_until(retriever, condition=lambda value: value,
|
|||
raise loopingcall.LoopingCallDone(retvalue=obj)
|
||||
if time_out is not None and time.time() - start_time > time_out:
|
||||
raise exception.PollTimeOut
|
||||
lc = loopingcall.LoopingCall(f=poll_and_check).start(sleep_time, True)
|
||||
|
||||
lc = loopingcall.FixedIntervalLoopingCall(
|
||||
f=poll_and_check).start(
|
||||
sleep_time, True)
|
||||
|
||||
return lc.wait()
|
||||
|
||||
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
|
||||
import webob.exc
|
||||
|
||||
from oslo.utils import strutils
|
||||
|
||||
from trove.common import exception
|
||||
from trove.common import pagination
|
||||
from trove.common import wsgi
|
||||
|
@ -82,8 +84,8 @@ class UserController(wsgi.Controller):
|
|||
def create(self, req, body, tenant_id, instance_id):
|
||||
"""Creates a set of users."""
|
||||
LOG.info(_("Creating users for instance '%s'") % instance_id)
|
||||
LOG.info(_("req : '%s'\n\n") % logging.mask_password(req))
|
||||
LOG.info(_("body : '%s'\n\n") % logging.mask_password(body))
|
||||
LOG.info(_("req : '%s'\n\n") % strutils.mask_password(req))
|
||||
LOG.info(_("body : '%s'\n\n") % strutils.mask_password(body))
|
||||
context = req.environ[wsgi.CONTEXT_KEY]
|
||||
users = body['users']
|
||||
try:
|
||||
|
@ -135,7 +137,7 @@ class UserController(wsgi.Controller):
|
|||
def update(self, req, body, tenant_id, instance_id, id):
|
||||
"""Change attributes for one user."""
|
||||
LOG.info(_("Updating user attributes for instance '%s'") % instance_id)
|
||||
LOG.info(_("req : '%s'\n\n") % logging.mask_password(req))
|
||||
LOG.info(_("req : '%s'\n\n") % strutils.mask_password(req))
|
||||
context = req.environ[wsgi.CONTEXT_KEY]
|
||||
id = correct_id_with_req(id, req)
|
||||
username, hostname = unquote_user_host(id)
|
||||
|
@ -157,7 +159,7 @@ class UserController(wsgi.Controller):
|
|||
def update_all(self, req, body, tenant_id, instance_id):
|
||||
"""Change the password of one or more users."""
|
||||
LOG.info(_("Updating user passwords for instance '%s'") % instance_id)
|
||||
LOG.info(_("req : '%s'\n\n") % logging.mask_password(req))
|
||||
LOG.info(_("req : '%s'\n\n") % strutils.mask_password(req))
|
||||
context = req.environ[wsgi.CONTEXT_KEY]
|
||||
users = body['users']
|
||||
model_users = []
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
|
||||
import webob.exc
|
||||
|
||||
from oslo.utils import strutils
|
||||
|
||||
from trove.common import cfg
|
||||
from trove.common import exception
|
||||
from trove.common import pagination
|
||||
|
@ -184,8 +186,8 @@ class InstanceController(wsgi.Controller):
|
|||
# TODO(hub-cap): turn this into middleware
|
||||
LOG.info(_LI("Creating a database instance for tenant '%s'"),
|
||||
tenant_id)
|
||||
LOG.debug("req : '%s'\n\n", logging.mask_password(req))
|
||||
LOG.debug("body : '%s'\n\n", logging.mask_password(body))
|
||||
LOG.debug("req : '%s'\n\n", strutils.mask_password(req))
|
||||
LOG.debug("body : '%s'\n\n", strutils.mask_password(body))
|
||||
context = req.environ[wsgi.CONTEXT_KEY]
|
||||
datastore_args = body['instance'].get('datastore', {})
|
||||
datastore, datastore_version = (
|
||||
|
@ -273,8 +275,8 @@ class InstanceController(wsgi.Controller):
|
|||
Updates the instance to set or unset one or more attributes.
|
||||
"""
|
||||
LOG.info(_LI("Editing instance for tenant id %s."), tenant_id)
|
||||
LOG.debug("req: %s", logging.mask_password(req))
|
||||
LOG.debug("body: %s", logging.mask_password(body))
|
||||
LOG.debug("req: %s", strutils.mask_password(req))
|
||||
LOG.debug("body: %s", strutils.mask_password(body))
|
||||
context = req.environ[wsgi.CONTEXT_KEY]
|
||||
|
||||
instance = models.Instance.load(context, id)
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
#
|
||||
# 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.
|
||||
|
||||
import six
|
||||
|
||||
|
||||
six.add_move(six.MovedModule('mox', 'mox', 'mox3.mox'))
|
|
@ -0,0 +1,45 @@
|
|||
# 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
|
||||
|
||||
"""
|
||||
|
||||
try:
|
||||
import oslo.i18n
|
||||
|
||||
# NOTE(dhellmann): This reference to o-s-l-o will be replaced by the
|
||||
# application name when this module is synced into the separate
|
||||
# repository. It is OK to have more than one translation function
|
||||
# using the same domain, since there will still only be one message
|
||||
# catalog.
|
||||
_translators = oslo.i18n.TranslatorFactory(domain='trove')
|
||||
|
||||
# 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
|
||||
except ImportError:
|
||||
# NOTE(dims): Support for cases where a project wants to use
|
||||
# code from trove-incubator, but is not ready to be internationalized
|
||||
# (like tempest)
|
||||
_ = _LI = _LW = _LE = _LC = lambda x: x
|
|
@ -25,7 +25,7 @@ import uuid
|
|||
|
||||
|
||||
def generate_request_id():
|
||||
return 'req-%s' % str(uuid.uuid4())
|
||||
return b'req-' + str(uuid.uuid4()).encode('ascii')
|
||||
|
||||
|
||||
class RequestContext(object):
|
||||
|
@ -77,6 +77,21 @@ class RequestContext(object):
|
|||
'instance_uuid': self.instance_uuid,
|
||||
'user_identity': user_idt}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, ctx):
|
||||
return cls(
|
||||
auth_token=ctx.get("auth_token"),
|
||||
user=ctx.get("user"),
|
||||
tenant=ctx.get("tenant"),
|
||||
domain=ctx.get("domain"),
|
||||
user_domain=ctx.get("user_domain"),
|
||||
project_domain=ctx.get("project_domain"),
|
||||
is_admin=ctx.get("is_admin", False),
|
||||
read_only=ctx.get("read_only", False),
|
||||
show_deleted=ctx.get("show_deleted", False),
|
||||
request_id=ctx.get("request_id"),
|
||||
instance_uuid=ctx.get("instance_uuid"))
|
||||
|
||||
|
||||
def get_admin_context(show_deleted=False):
|
||||
context = RequestContext(None,
|
||||
|
@ -98,3 +113,10 @@ def get_context_from_function_and_args(function, args, kwargs):
|
|||
return arg
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def is_user_context(context):
|
||||
"""Indicates if the request context is a normal user."""
|
||||
if not context or context.is_admin:
|
||||
return False
|
||||
return context.user_id and context.project_id
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright (c) 2012 OpenStack Foundation.
|
||||
# Administrator of the National Aeronautics and Space Administration.
|
||||
# All Rights Reserved.
|
||||
|
@ -18,6 +16,7 @@
|
|||
|
||||
from __future__ import print_function
|
||||
|
||||
import copy
|
||||
import errno
|
||||
import gc
|
||||
import os
|
||||
|
@ -31,7 +30,7 @@ import eventlet.backdoor
|
|||
import greenlet
|
||||
from oslo.config import cfg
|
||||
|
||||
from trove.openstack.common.gettextutils import _ # noqa
|
||||
from trove.openstack.common._i18n import _LI
|
||||
from trove.openstack.common import log as logging
|
||||
|
||||
help_for_backdoor_port = (
|
||||
|
@ -43,7 +42,6 @@ help_for_backdoor_port = (
|
|||
"chosen port is displayed in the service's log file.")
|
||||
eventlet_backdoor_opts = [
|
||||
cfg.StrOpt('backdoor_port',
|
||||
default=None,
|
||||
help="Enable eventlet backdoor. %s" % help_for_backdoor_port)
|
||||
]
|
||||
|
||||
|
@ -52,6 +50,12 @@ CONF.register_opts(eventlet_backdoor_opts)
|
|||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def list_opts():
|
||||
"""Entry point for oslo.config-generator.
|
||||
"""
|
||||
return [(None, copy.deepcopy(eventlet_backdoor_opts))]
|
||||
|
||||
|
||||
class EventletBackdoorConfigValueError(Exception):
|
||||
def __init__(self, port_range, help_msg, ex):
|
||||
msg = ('Invalid backdoor_port configuration %(range)s: %(ex)s. '
|
||||
|
@ -66,7 +70,7 @@ def _dont_use_this():
|
|||
|
||||
|
||||
def _find_objects(t):
|
||||
return filter(lambda o: isinstance(o, t), gc.get_objects())
|
||||
return [o for o in gc.get_objects() if isinstance(o, t)]
|
||||
|
||||
|
||||
def _print_greenthreads():
|
||||
|
@ -139,8 +143,10 @@ def initialize_if_enabled():
|
|||
# In the case of backdoor port being zero, a port number is assigned by
|
||||
# listen(). In any case, pull the port number out here.
|
||||
port = sock.getsockname()[1]
|
||||
LOG.info(_('Eventlet backdoor listening on %(port)s for process %(pid)d') %
|
||||
{'port': port, 'pid': os.getpid()})
|
||||
LOG.info(
|
||||
_LI('Eventlet backdoor listening on %(port)s for process %(pid)d') %
|
||||
{'port': port, 'pid': os.getpid()}
|
||||
)
|
||||
eventlet.spawn_n(eventlet.backdoor.backdoor_server, sock,
|
||||
locals=backdoor_locals)
|
||||
return port
|
||||
|
|
|
@ -27,28 +27,27 @@ It also allows setting of formatting information through conf.
|
|||
|
||||
"""
|
||||
|
||||
import copy
|
||||
import inspect
|
||||
import itertools
|
||||
import logging
|
||||
import logging.config
|
||||
import logging.handlers
|
||||
import os
|
||||
import socket
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
from oslo.config import cfg
|
||||
from oslo.serialization import jsonutils
|
||||
from oslo.utils import importutils
|
||||
import six
|
||||
from six import moves
|
||||
|
||||
_PY26 = sys.version_info[0:2] == (2, 6)
|
||||
|
||||
from trove.openstack.common.gettextutils import _
|
||||
from trove.openstack.common import importutils
|
||||
from trove.openstack.common import jsonutils
|
||||
from trove.openstack.common._i18n import _
|
||||
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"
|
||||
|
@ -126,7 +125,9 @@ 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']
|
||||
'urllib3.connectionpool=WARN', 'websocket=WARN',
|
||||
"keystonemiddleware=WARN", "routes.middleware=WARN",
|
||||
"stevedore=WARN"]
|
||||
|
||||
log_opts = [
|
||||
cfg.StrOpt('logging_context_format_string',
|
||||
|
@ -174,6 +175,16 @@ CONF.register_cli_opts(logging_cli_opts)
|
|||
CONF.register_opts(generic_log_opts)
|
||||
CONF.register_opts(log_opts)
|
||||
|
||||
|
||||
def list_opts():
|
||||
"""Entry point for oslo.config-generator."""
|
||||
return [(None, copy.deepcopy(common_cli_opts)),
|
||||
(None, copy.deepcopy(logging_cli_opts)),
|
||||
(None, copy.deepcopy(generic_log_opts)),
|
||||
(None, copy.deepcopy(log_opts)),
|
||||
]
|
||||
|
||||
|
||||
# our new audit level
|
||||
# NOTE(jkoelker) Since we synthesized an audit level, make the logging
|
||||
# module aware of it so it acts like other levels.
|
||||
|
@ -300,11 +311,10 @@ class ContextAdapter(BaseLoggerAdapter):
|
|||
self.warn(stdmsg, *args, **kwargs)
|
||||
|
||||
def process(self, msg, kwargs):
|
||||
# NOTE(mrodden): catch any Message/other object and
|
||||
# coerce to unicode before they can get
|
||||
# to the python logging and possibly
|
||||
# cause string encoding trouble
|
||||
if not isinstance(msg, six.string_types):
|
||||
# NOTE(jecarey): If msg is not unicode, coerce it into unicode
|
||||
# before it can get to the python logging and
|
||||
# possibly cause string encoding trouble
|
||||
if not isinstance(msg, six.text_type):
|
||||
msg = six.text_type(msg)
|
||||
|
||||
if 'extra' not in kwargs:
|
||||
|
@ -429,12 +439,12 @@ def set_defaults(logging_context_format_string=None,
|
|||
# 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)
|
||||
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)
|
||||
log_opts,
|
||||
logging_context_format_string=logging_context_format_string)
|
||||
|
||||
|
||||
def _find_facility_from_conf():
|
||||
|
@ -483,18 +493,6 @@ def _setup_logging_from_conf(project, version):
|
|||
for handler in log_root.handlers:
|
||||
log_root.removeHandler(handler)
|
||||
|
||||
if CONF.use_syslog:
|
||||
facility = _find_facility_from_conf()
|
||||
# TODO(bogdando) use the format provided by RFCSysLogHandler
|
||||
# after existing syslog format deprecation in J
|
||||
if CONF.use_syslog_rfc_format:
|
||||
syslog = RFCSysLogHandler(address='/dev/log',
|
||||
facility=facility)
|
||||
else:
|
||||
syslog = logging.handlers.SysLogHandler(address='/dev/log',
|
||||
facility=facility)
|
||||
log_root.addHandler(syslog)
|
||||
|
||||
logpath = _get_log_file_path()
|
||||
if logpath:
|
||||
filelog = logging.handlers.WatchedFileHandler(logpath)
|
||||
|
@ -511,14 +509,9 @@ def _setup_logging_from_conf(project, version):
|
|||
log_root.addHandler(streamlog)
|
||||
|
||||
if CONF.publish_errors:
|
||||
try:
|
||||
handler = importutils.import_object(
|
||||
"trove.openstack.common.log_handler.PublishErrorsHandler",
|
||||
logging.ERROR)
|
||||
except ImportError:
|
||||
handler = importutils.import_object(
|
||||
"oslo.messaging.notify.log_handler.PublishErrorsHandler",
|
||||
logging.ERROR)
|
||||
handler = importutils.import_object(
|
||||
"oslo.messaging.notify.log_handler.PublishErrorsHandler",
|
||||
logging.ERROR)
|
||||
log_root.addHandler(handler)
|
||||
|
||||
datefmt = CONF.log_date_format
|
||||
|
@ -553,6 +546,22 @@ def _setup_logging_from_conf(project, version):
|
|||
else:
|
||||
logger.setLevel(level_name)
|
||||
|
||||
if CONF.use_syslog:
|
||||
try:
|
||||
facility = _find_facility_from_conf()
|
||||
# TODO(bogdando) use the format provided by RFCSysLogHandler
|
||||
# after existing syslog format deprecation in J
|
||||
if CONF.use_syslog_rfc_format:
|
||||
syslog = RFCSysLogHandler(address='/dev/log',
|
||||
facility=facility)
|
||||
else:
|
||||
syslog = logging.handlers.SysLogHandler(address='/dev/log',
|
||||
facility=facility)
|
||||
log_root.addHandler(syslog)
|
||||
except socket.error:
|
||||
log_root.error('Unable to add syslog handler. Verify that syslog '
|
||||
'is running.')
|
||||
|
||||
|
||||
_loggers = {}
|
||||
|
||||
|
@ -622,6 +631,12 @@ class ContextFormatter(logging.Formatter):
|
|||
def format(self, record):
|
||||
"""Uses contextstring if request_id is set, otherwise default."""
|
||||
|
||||
# NOTE(jecarey): If msg is not unicode, coerce it into unicode
|
||||
# before it can get to the python logging and
|
||||
# possibly cause string encoding trouble
|
||||
if not isinstance(record.msg, six.text_type):
|
||||
record.msg = six.text_type(record.msg)
|
||||
|
||||
# store project info
|
||||
record.project = self.project
|
||||
record.version = self.version
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2010 United States Government as represented by the
|
||||
# Administrator of the National Aeronautics and Space Administration.
|
||||
# Copyright 2011 Justin Santa Barbara
|
||||
|
@ -18,31 +16,36 @@
|
|||
# under the License.
|
||||
|
||||
import sys
|
||||
import time
|
||||
|
||||
from eventlet import event
|
||||
from eventlet import greenthread
|
||||
|
||||
from trove.openstack.common.gettextutils import _ # noqa
|
||||
from trove.openstack.common._i18n import _LE, _LW
|
||||
from trove.openstack.common import log as logging
|
||||
from trove.openstack.common import timeutils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
# NOTE(zyluo): This lambda function was declared to avoid mocking collisions
|
||||
# with time.time() called in the standard logging module
|
||||
# during unittests.
|
||||
_ts = lambda: time.time()
|
||||
|
||||
|
||||
class LoopingCallDone(Exception):
|
||||
"""Exception to break out and stop a LoopingCall.
|
||||
"""Exception to break out and stop a LoopingCallBase.
|
||||
|
||||
The poll-function passed to LoopingCall can raise this exception to
|
||||
The poll-function passed to LoopingCallBase can raise this exception to
|
||||
break out of the loop normally. This is somewhat analogous to
|
||||
StopIteration.
|
||||
|
||||
An optional return-value can be included as the argument to the exception;
|
||||
this return-value will be returned by LoopingCall.wait()
|
||||
this return-value will be returned by LoopingCallBase.wait()
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, retvalue=True):
|
||||
""":param retvalue: Value that LoopingCall.wait() should return."""
|
||||
""":param retvalue: Value that LoopingCallBase.wait() should return."""
|
||||
self.retvalue = retvalue
|
||||
|
||||
|
||||
|
@ -74,21 +77,22 @@ class FixedIntervalLoopingCall(LoopingCallBase):
|
|||
|
||||
try:
|
||||
while self._running:
|
||||
start = timeutils.utcnow()
|
||||
start = _ts()
|
||||
self.f(*self.args, **self.kw)
|
||||
end = timeutils.utcnow()
|
||||
end = _ts()
|
||||
if not self._running:
|
||||
break
|
||||
delay = interval - timeutils.delta_seconds(start, end)
|
||||
if delay <= 0:
|
||||
LOG.warn(_('task run outlasted interval by %s sec') %
|
||||
-delay)
|
||||
greenthread.sleep(delay if delay > 0 else 0)
|
||||
delay = end - start - interval
|
||||
if delay > 0:
|
||||
LOG.warn(_LW('task %(func_name)s run outlasted '
|
||||
'interval by %(delay).2f sec'),
|
||||
{'func_name': repr(self.f), 'delay': delay})
|
||||
greenthread.sleep(-delay if delay < 0 else 0)
|
||||
except LoopingCallDone as e:
|
||||
self.stop()
|
||||
done.send(e.retvalue)
|
||||
except Exception:
|
||||
LOG.exception(_('in fixed duration looping call'))
|
||||
LOG.exception(_LE('in fixed duration looping call'))
|
||||
done.send_exception(*sys.exc_info())
|
||||
return
|
||||
else:
|
||||
|
@ -100,11 +104,6 @@ class FixedIntervalLoopingCall(LoopingCallBase):
|
|||
return self.done
|
||||
|
||||
|
||||
# TODO(mikal): this class name is deprecated in Havana and should be removed
|
||||
# in the I release
|
||||
LoopingCall = FixedIntervalLoopingCall
|
||||
|
||||
|
||||
class DynamicLoopingCall(LoopingCallBase):
|
||||
"""A looping call which sleeps until the next known event.
|
||||
|
||||
|
@ -128,14 +127,15 @@ class DynamicLoopingCall(LoopingCallBase):
|
|||
|
||||
if periodic_interval_max is not None:
|
||||
idle = min(idle, periodic_interval_max)
|
||||
LOG.debug(_('Dynamic looping call sleeping for %.02f '
|
||||
'seconds'), idle)
|
||||
LOG.debug('Dynamic looping call %(func_name)s sleeping '
|
||||
'for %(idle).02f seconds',
|
||||
{'func_name': repr(self.f), 'idle': idle})
|
||||
greenthread.sleep(idle)
|
||||
except LoopingCallDone as e:
|
||||
self.stop()
|
||||
done.send(e.retvalue)
|
||||
except Exception:
|
||||
LOG.exception(_('in dynamic looping call'))
|
||||
LOG.exception(_LE('in dynamic looping call'))
|
||||
done.send_exception(*sys.exc_info())
|
||||
return
|
||||
else:
|
||||
|
|
|
@ -38,7 +38,7 @@ from eventlet import event
|
|||
from oslo.config import cfg
|
||||
|
||||
from trove.openstack.common import eventlet_backdoor
|
||||
from trove.openstack.common.gettextutils import _LE, _LI, _LW
|
||||
from trove.openstack.common._i18n import _LE, _LI, _LW
|
||||
from trove.openstack.common import log as logging
|
||||
from trove.openstack.common import systemd
|
||||
from trove.openstack.common import threadgroup
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2012 Red Hat, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
|
@ -13,10 +11,10 @@
|
|||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import threading
|
||||
|
||||
import eventlet
|
||||
from eventlet import greenpool
|
||||
from eventlet import greenthread
|
||||
|
||||
from trove.openstack.common import log as logging
|
||||
from trove.openstack.common import loopingcall
|
||||
|
@ -48,9 +46,12 @@ class Thread(object):
|
|||
def wait(self):
|
||||
return self.thread.wait()
|
||||
|
||||
def link(self, func, *args, **kwargs):
|
||||
self.thread.link(func, *args, **kwargs)
|
||||
|
||||
|
||||
class ThreadGroup(object):
|
||||
"""The point of the ThreadGroup classis to:
|
||||
"""The point of the ThreadGroup class is to:
|
||||
|
||||
* keep track of timers and greenthreads (making it easier to stop them
|
||||
when need be).
|
||||
|
@ -79,21 +80,28 @@ class ThreadGroup(object):
|
|||
gt = self.pool.spawn(callback, *args, **kwargs)
|
||||
th = Thread(gt, self)
|
||||
self.threads.append(th)
|
||||
return th
|
||||
|
||||
def thread_done(self, thread):
|
||||
self.threads.remove(thread)
|
||||
|
||||
def stop(self):
|
||||
current = greenthread.getcurrent()
|
||||
for x in self.threads:
|
||||
def _stop_threads(self):
|
||||
current = threading.current_thread()
|
||||
|
||||
# Iterate over a copy of self.threads so thread_done doesn't
|
||||
# modify the list while we're iterating
|
||||
for x in self.threads[:]:
|
||||
if x is current:
|
||||
# don't kill the current thread.
|
||||
continue
|
||||
try:
|
||||
x.stop()
|
||||
except eventlet.greenlet.GreenletExit:
|
||||
pass
|
||||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
|
||||
def stop_timers(self):
|
||||
for x in self.timers:
|
||||
try:
|
||||
x.stop()
|
||||
|
@ -101,6 +109,23 @@ class ThreadGroup(object):
|
|||
LOG.exception(ex)
|
||||
self.timers = []
|
||||
|
||||
def stop(self, graceful=False):
|
||||
"""stop function has the option of graceful=True/False.
|
||||
|
||||
* In case of graceful=True, wait for all threads to be finished.
|
||||
Never kill threads.
|
||||
* In case of graceful=False, kill threads immediately.
|
||||
"""
|
||||
self.stop_timers()
|
||||
if graceful:
|
||||
# In case of graceful=True, wait for all threads to be
|
||||
# finished, never kill threads
|
||||
self.wait()
|
||||
else:
|
||||
# In case of graceful=False(Default), kill threads
|
||||
# immediately
|
||||
self._stop_threads()
|
||||
|
||||
def wait(self):
|
||||
for x in self.timers:
|
||||
try:
|
||||
|
@ -109,8 +134,11 @@ class ThreadGroup(object):
|
|||
pass
|
||||
except Exception as ex:
|
||||
LOG.exception(ex)
|
||||
current = greenthread.getcurrent()
|
||||
for x in self.threads:
|
||||
current = threading.current_thread()
|
||||
|
||||
# Iterate over a copy of self.threads so thread_done doesn't
|
||||
# modify the list while we're iterating
|
||||
for x in self.threads[:]:
|
||||
if x is current:
|
||||
continue
|
||||
try:
|
||||
|
|
|
@ -18,9 +18,12 @@ Helpers for comparing version strings.
|
|||
"""
|
||||
|
||||
import functools
|
||||
import pkg_resources
|
||||
import inspect
|
||||
|
||||
from trove.openstack.common.gettextutils import _
|
||||
import pkg_resources
|
||||
import six
|
||||
|
||||
from trove.openstack.common._i18n import _
|
||||
from trove.openstack.common import log as logging
|
||||
|
||||
|
||||
|
@ -52,18 +55,36 @@ class deprecated(object):
|
|||
>>> @deprecated(as_of=deprecated.ICEHOUSE, remove_in=+1)
|
||||
... def c(): pass
|
||||
|
||||
4. Specifying the deprecated functionality will not be removed:
|
||||
>>> @deprecated(as_of=deprecated.ICEHOUSE, remove_in=0)
|
||||
... def d(): pass
|
||||
|
||||
5. Specifying a replacement, deprecated functionality will not be removed:
|
||||
>>> @deprecated(as_of=deprecated.ICEHOUSE, in_favor_of='f()', remove_in=0)
|
||||
... def e(): pass
|
||||
|
||||
"""
|
||||
|
||||
# NOTE(morganfainberg): Bexar is used for unit test purposes, it is
|
||||
# expected we maintain a gap between Bexar and Folsom in this list.
|
||||
BEXAR = 'B'
|
||||
FOLSOM = 'F'
|
||||
GRIZZLY = 'G'
|
||||
HAVANA = 'H'
|
||||
ICEHOUSE = 'I'
|
||||
JUNO = 'J'
|
||||
KILO = 'K'
|
||||
|
||||
_RELEASES = {
|
||||
# NOTE(morganfainberg): Bexar is used for unit test purposes, it is
|
||||
# expected we maintain a gap between Bexar and Folsom in this list.
|
||||
'B': 'Bexar',
|
||||
'F': 'Folsom',
|
||||
'G': 'Grizzly',
|
||||
'H': 'Havana',
|
||||
'I': 'Icehouse',
|
||||
'J': 'Juno',
|
||||
'K': 'Kilo',
|
||||
}
|
||||
|
||||
_deprecated_msg_with_alternative = _(
|
||||
|
@ -74,6 +95,12 @@ class deprecated(object):
|
|||
'%(what)s is deprecated as of %(as_of)s and may be '
|
||||
'removed in %(remove_in)s. It will not be superseded.')
|
||||
|
||||
_deprecated_msg_with_alternative_no_removal = _(
|
||||
'%(what)s is deprecated as of %(as_of)s in favor of %(in_favor_of)s.')
|
||||
|
||||
_deprecated_msg_with_no_alternative_no_removal = _(
|
||||
'%(what)s is deprecated as of %(as_of)s. It will not be superseded.')
|
||||
|
||||
def __init__(self, as_of, in_favor_of=None, remove_in=2, what=None):
|
||||
"""Initialize decorator
|
||||
|
||||
|
@ -91,16 +118,34 @@ class deprecated(object):
|
|||
self.remove_in = remove_in
|
||||
self.what = what
|
||||
|
||||
def __call__(self, func):
|
||||
def __call__(self, func_or_cls):
|
||||
if not self.what:
|
||||
self.what = func.__name__ + '()'
|
||||
self.what = func_or_cls.__name__ + '()'
|
||||
msg, details = self._build_message()
|
||||
|
||||
@functools.wraps(func)
|
||||
def wrapped(*args, **kwargs):
|
||||
msg, details = self._build_message()
|
||||
LOG.deprecated(msg, details)
|
||||
return func(*args, **kwargs)
|
||||
return wrapped
|
||||
if inspect.isfunction(func_or_cls):
|
||||
|
||||
@six.wraps(func_or_cls)
|
||||
def wrapped(*args, **kwargs):
|
||||
LOG.deprecated(msg, details)
|
||||
return func_or_cls(*args, **kwargs)
|
||||
return wrapped
|
||||
elif inspect.isclass(func_or_cls):
|
||||
orig_init = func_or_cls.__init__
|
||||
|
||||
# TODO(tsufiev): change `functools` module to `six` as
|
||||
# soon as six 1.7.4 (with fix for passing `assigned`
|
||||
# argument to underlying `functools.wraps`) is released
|
||||
# and added to the trove-incubator requrements
|
||||
@functools.wraps(orig_init, assigned=('__name__', '__doc__'))
|
||||
def new_init(self, *args, **kwargs):
|
||||
LOG.deprecated(msg, details)
|
||||
orig_init(self, *args, **kwargs)
|
||||
func_or_cls.__init__ = new_init
|
||||
return func_or_cls
|
||||
else:
|
||||
raise TypeError('deprecated can be used only with functions or '
|
||||
'classes')
|
||||
|
||||
def _get_safe_to_remove_release(self, release):
|
||||
# TODO(dstanek): this method will have to be reimplemented once
|
||||
|
@ -119,9 +164,19 @@ class deprecated(object):
|
|||
|
||||
if self.in_favor_of:
|
||||
details['in_favor_of'] = self.in_favor_of
|
||||
msg = self._deprecated_msg_with_alternative
|
||||
if self.remove_in > 0:
|
||||
msg = self._deprecated_msg_with_alternative
|
||||
else:
|
||||
# There are no plans to remove this function, but it is
|
||||
# now deprecated.
|
||||
msg = self._deprecated_msg_with_alternative_no_removal
|
||||
else:
|
||||
msg = self._deprecated_msg_no_alternative
|
||||
if self.remove_in > 0:
|
||||
msg = self._deprecated_msg_no_alternative
|
||||
else:
|
||||
# There are no plans to remove this function, but it is
|
||||
# now deprecated.
|
||||
msg = self._deprecated_msg_with_no_alternative_no_removal
|
||||
return msg, details
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue