Merge "Sync with oslo-incubator"

This commit is contained in:
Jenkins 2015-02-13 15:23:02 +00:00 committed by Gerrit Code Review
commit 2495849456
14 changed files with 256 additions and 40 deletions

View File

@ -19,6 +19,7 @@ from __future__ import print_function
import copy
import errno
import gc
import logging
import os
import pprint
import socket
@ -30,7 +31,6 @@ import greenlet
from oslo_config import cfg
from nova.openstack.common._i18n import _LI
from nova.openstack.common import log as logging
help_for_backdoor_port = (
"Acceptable values are 0, <port>, and <start>:<end>, where 0 results "

View File

@ -17,6 +17,7 @@ import contextlib
import errno
import logging
import os
import stat
import tempfile
from oslo_utils import excutils
@ -24,15 +25,17 @@ from oslo_utils import excutils
LOG = logging.getLogger(__name__)
_FILE_CACHE = {}
DEFAULT_MODE = stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO
def ensure_tree(path):
def ensure_tree(path, mode=DEFAULT_MODE):
"""Create a directory (and any ancestor directories required)
:param path: Directory to create
:param mode: Directory creation permissions
"""
try:
os.makedirs(path)
os.makedirs(path, mode)
except OSError as exc:
if exc.errno == errno.EEXIST:
if not os.path.isdir(path):

View File

@ -15,6 +15,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import logging
import sys
import time
@ -22,7 +23,6 @@ from eventlet import event
from eventlet import greenthread
from nova.openstack.common._i18n import _LE, _LW
from nova.openstack.common import log as logging
LOG = logging.getLogger(__name__)

View File

@ -12,6 +12,7 @@
# under the License.
import copy
import logging
import random
import time
@ -19,7 +20,6 @@ from oslo_config import cfg
import six
from nova.openstack.common._i18n import _, _LE, _LI
from nova.openstack.common import log as logging
periodic_opts = [
@ -55,14 +55,15 @@ def periodic_task(*args, **kwargs):
interval of 60 seconds.
2. With arguments:
@periodic_task(spacing=N [, run_immediately=[True|False]])
@periodic_task(spacing=N [, run_immediately=[True|False]]
[, name=[None|"string"])
this will be run on approximately every N seconds. If this number is
negative the periodic task will be disabled. If the run_immediately
argument is provided and has a value of 'True', the first run of the
task will be shortly after task scheduler starts. If
run_immediately is omitted or set to 'False', the first time the
task runs will be approximately N seconds after the task scheduler
starts.
starts. If name is not provided, __name__ of function is used.
"""
def decorator(f):
# Test for old style invocation
@ -76,6 +77,7 @@ def periodic_task(*args, **kwargs):
f._periodic_enabled = False
else:
f._periodic_enabled = kwargs.pop('enabled', True)
f._periodic_name = kwargs.pop('name', f.__name__)
# Control frequency
f._periodic_spacing = kwargs.pop('spacing', 0)
@ -105,6 +107,36 @@ def periodic_task(*args, **kwargs):
class _PeriodicTasksMeta(type):
def _add_periodic_task(cls, task):
"""Add a periodic task to the list of periodic tasks.
The task should already be decorated by @periodic_task.
:return: whether task was actually enabled
"""
name = task._periodic_name
if task._periodic_spacing < 0:
LOG.info(_LI('Skipping periodic task %(task)s because '
'its interval is negative'),
{'task': name})
return False
if not task._periodic_enabled:
LOG.info(_LI('Skipping periodic task %(task)s because '
'it is disabled'),
{'task': name})
return False
# A periodic spacing of zero indicates that this task should
# be run on the default interval to avoid running too
# frequently.
if task._periodic_spacing == 0:
task._periodic_spacing = DEFAULT_INTERVAL
cls._periodic_tasks.append((name, task))
cls._periodic_spacing[name] = task._periodic_spacing
return True
def __init__(cls, names, bases, dict_):
"""Metaclass that allows us to collect decorated periodic tasks."""
super(_PeriodicTasksMeta, cls).__init__(names, bases, dict_)
@ -125,28 +157,7 @@ class _PeriodicTasksMeta(type):
for value in cls.__dict__.values():
if getattr(value, '_periodic_task', False):
task = value
name = task.__name__
if task._periodic_spacing < 0:
LOG.info(_LI('Skipping periodic task %(task)s because '
'its interval is negative'),
{'task': name})
continue
if not task._periodic_enabled:
LOG.info(_LI('Skipping periodic task %(task)s because '
'it is disabled'),
{'task': name})
continue
# A periodic spacing of zero indicates that this task should
# be run on the default interval to avoid running too
# frequently.
if task._periodic_spacing == 0:
task._periodic_spacing = DEFAULT_INTERVAL
cls._periodic_tasks.append((name, task))
cls._periodic_spacing[name] = task._periodic_spacing
cls._add_periodic_task(value)
def _nearest_boundary(last_run, spacing):
@ -178,6 +189,15 @@ class PeriodicTasks(object):
for name, task in self._periodic_tasks:
self._periodic_last_run[name] = task._periodic_last_run
def add_periodic_task(self, task):
"""Add a periodic task to the list of periodic tasks.
The task should already be decorated by @periodic_task.
"""
if self.__class__._add_periodic_task(task):
self._periodic_last_run[task._periodic_name] = (
task._periodic_last_run)
def run_periodic_tasks(self, context, raise_on_error=False):
"""Tasks to be run at a periodic interval."""
idle_for = DEFAULT_INTERVAL

View File

@ -91,6 +91,7 @@ as it allows particular rules to be explicitly disabled.
import abc
import ast
import copy
import logging
import os
import re
@ -102,7 +103,6 @@ import six.moves.urllib.request as urlrequest
from nova.openstack.common import fileutils
from nova.openstack.common._i18n import _, _LE, _LI
from nova.openstack.common import log as logging
policy_opts = [

View File

@ -0,0 +1,38 @@
# Copyright 2014 Red Hat, Inc.
#
# 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.
"""Provides process-data generators
This modules defines a class for generating
process data by way of the psutil package.
"""
import os
import psutil
from nova.openstack.common.report.models import process as pm
class ProcessReportGenerator(object):
"""A Process Data Generator
This generator returns a
:class:`openstack.common.report.models.process.ProcessModel`
based on the current process (which will also include
all subprocesses, recursively) using the :class:`psutil.Process` class`.
"""
def __call__(self):
return pm.ProcessModel(psutil.Process(os.getpid()))

View File

@ -59,6 +59,7 @@ import sys
from oslo_utils import timeutils
from nova.openstack.common.report.generators import conf as cgen
from nova.openstack.common.report.generators import process as prgen
from nova.openstack.common.report.generators import threading as tgen
from nova.openstack.common.report.generators import version as pgen
from nova.openstack.common.report import report
@ -179,6 +180,9 @@ class GuruMeditation(object):
self.add_section('Green Threads',
tgen.GreenThreadReportGenerator())
self.add_section('Processes',
prgen.ProcessReportGenerator())
self.add_section('Configuration',
cgen.ConfigReportGenerator())
@ -208,6 +212,8 @@ class TextGuruMeditation(GuruMeditation, report.TextReport):
- Green Threads List
- Process List
- Configuration Options
:param version_obj: the version object for the current product

View File

@ -0,0 +1,62 @@
# Copyright 2014 Red Hat, Inc.
#
# 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.
"""Provides a process model
This module defines a class representing a process,
potentially with subprocesses.
"""
import nova.openstack.common.report.models.with_default_views as mwdv
import nova.openstack.common.report.views.text.process as text_views
class ProcessModel(mwdv.ModelWithDefaultViews):
"""A Process Model
This model holds data about a process,
including references to any subprocesses
:param process: a :class:`psutil.Process` object
"""
def __init__(self, process):
super(ProcessModel, self).__init__(
text_view=text_views.ProcessView())
self['pid'] = process.pid
self['parent_pid'] = process.ppid
if hasattr(process, 'uids'):
self['uids'] = {'real': process.uids.real,
'effective': process.uids.effective,
'saved': process.uids.saved}
else:
self['uids'] = {'real': None,
'effective': None,
'saved': None}
if hasattr(process, 'gids'):
self['gids'] = {'real': process.gids.real,
'effective': process.gids.effective,
'saved': process.gids.saved}
else:
self['gids'] = {'real': None,
'effective': None,
'saved': None}
self['username'] = process.username
self['command'] = process.cmdline
self['state'] = process.status
self['children'] = [ProcessModel(pr) for pr in process.get_children()]

View File

@ -0,0 +1,38 @@
# Copyright 2014 Red Hat, Inc.
#
# 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.
"""Provides process view
This module provides a view for
visualizing processes in human-readable formm
"""
import nova.openstack.common.report.views.jinja_view as jv
class ProcessView(jv.JinjaView):
"""A Process View
This view displays process models defined by
:class:`openstack.common.report.models.process.ProcessModel`
"""
VIEW_TEXT = (
"Process {{ pid }} (under {{ parent_pid }}) "
"[ run by: {{ username }} ({{ uids.real|default('unknown uid') }}),"
" state: {{ state }} ]\n"
"{% for child in children %}"
" {{ child }}"
"{% endfor %}"
)

View File

@ -18,7 +18,7 @@
"""Generic Node base class for all workers that run on hosts."""
import errno
import logging as std_logging
import logging
import os
import random
import signal
@ -39,7 +39,6 @@ from oslo_config import cfg
from nova.openstack.common import eventlet_backdoor
from nova.openstack.common._i18n import _LE, _LI, _LW
from nova.openstack.common import log as logging
from nova.openstack.common import systemd
from nova.openstack.common import threadgroup
@ -163,7 +162,7 @@ class ServiceLauncher(Launcher):
signo = 0
LOG.debug('Full set of CONF:')
CONF.log_opt_values(LOG, std_logging.DEBUG)
CONF.log_opt_values(LOG, logging.DEBUG)
try:
if ready_callback:
@ -377,7 +376,7 @@ class ProcessLauncher(object):
systemd.notify_once()
LOG.debug('Full set of CONF:')
CONF.log_opt_values(LOG, std_logging.DEBUG)
CONF.log_opt_values(LOG, logging.DEBUG)
try:
while True:

View File

@ -16,12 +16,11 @@
Helper module for systemd service readiness notification.
"""
import logging
import os
import socket
import sys
from nova.openstack.common import log as logging
LOG = logging.getLogger(__name__)

View File

@ -11,12 +11,12 @@
# 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 logging
import threading
import eventlet
from eventlet import greenpool
from nova.openstack.common import log as logging
from nova.openstack.common import loopingcall

View File

@ -19,15 +19,24 @@ Helpers for comparing version strings.
import functools
import inspect
import logging
from oslo.config import cfg
import pkg_resources
import six
from nova.openstack.common._i18n import _
from nova.openstack.common import log as logging
LOG = logging.getLogger(__name__)
CONF = cfg.CONF
opts = [
cfg.BoolOpt('fatal_deprecations',
default=False,
help='Enables or disables fatal status of deprecations.'),
]
class deprecated(object):
@ -127,7 +136,7 @@ class deprecated(object):
@six.wraps(func_or_cls)
def wrapped(*args, **kwargs):
LOG.deprecated(msg, details)
report_deprecated_feature(LOG, msg, details)
return func_or_cls(*args, **kwargs)
return wrapped
elif inspect.isclass(func_or_cls):
@ -139,7 +148,7 @@ class deprecated(object):
# and added to the oslo-incubator requrements
@functools.wraps(orig_init, assigned=('__name__', '__doc__'))
def new_init(self, *args, **kwargs):
LOG.deprecated(msg, details)
report_deprecated_feature(LOG, msg, details)
orig_init(self, *args, **kwargs)
func_or_cls.__init__ = new_init
return func_or_cls
@ -201,3 +210,44 @@ def is_compatible(requested_version, current_version, same_major=True):
return False
return current_parts >= requested_parts
# Track the messages we have sent already. See
# report_deprecated_feature().
_deprecated_messages_sent = {}
def report_deprecated_feature(logger, msg, *args, **kwargs):
"""Call this function when a deprecated feature is used.
If the system is configured for fatal deprecations then the message
is logged at the 'critical' level and :class:`DeprecatedConfig` will
be raised.
Otherwise, the message will be logged (once) at the 'warn' level.
:raises: :class:`DeprecatedConfig` if the system is configured for
fatal deprecations.
"""
stdmsg = _("Deprecated: %s") % msg
CONF.register_opts(opts)
if CONF.fatal_deprecations:
logger.critical(stdmsg, *args, **kwargs)
raise DeprecatedConfig(msg=stdmsg)
# Using a list because a tuple with dict can't be stored in a set.
sent_args = _deprecated_messages_sent.setdefault(msg, list())
if args in sent_args:
# Already logged this message, so don't log it again.
return
sent_args.append(args)
logger.warn(stdmsg, *args, **kwargs)
class DeprecatedConfig(Exception):
message = _("Fatal call to deprecated config: %(msg)s")
def __init__(self, msg):
super(Exception, self).__init__(self.message % dict(msg=msg))

View File

@ -41,3 +41,4 @@ oslo.i18n>=1.3.0 # Apache-2.0
rfc3986>=0.2.0 # Apache-2.0
oslo.vmware>=0.9.0 # Apache-2.0
oslo.middleware>=0.3.0 # Apache-2.0
psutil>=1.1.1,<2.0.0