diff options
-rw-r--r-- | openstack/common/log.py | 18 | ||||
-rw-r--r-- | openstack/common/log_handler.py | 31 | ||||
-rw-r--r-- | openstack/common/periodic_task.py | 1 | ||||
-rw-r--r-- | openstack/common/rootwrap/filters.py | 4 | ||||
-rw-r--r-- | openstack/common/rpc/common.py | 4 | ||||
-rw-r--r-- | openstack/common/rpc/proxy.py | 14 | ||||
-rw-r--r-- | openstack/common/service.py | 3 | ||||
-rw-r--r-- | openstack/common/threadgroup.py | 7 | ||||
-rw-r--r-- | tests/unit/db/sqlalchemy/test_sqlalchemy.py | 2 | ||||
-rw-r--r-- | tests/unit/rpc/common.py | 2 | ||||
-rw-r--r-- | tests/unit/rpc/test_common.py | 2 | ||||
-rw-r--r-- | tests/unit/rpc/test_kombu.py | 2 | ||||
-rw-r--r-- | tests/unit/rpc/test_proxy.py | 8 | ||||
-rw-r--r-- | tests/unit/rpc/test_qpid.py | 2 | ||||
-rw-r--r-- | tests/unit/test_log.py | 3 | ||||
-rw-r--r-- | tests/unit/test_rootwrap.py | 12 | ||||
-rw-r--r-- | tests/unit/test_service.py | 10 | ||||
-rw-r--r-- | tests/unit/test_setup.py | 2 | ||||
-rw-r--r-- | tests/unit/test_threadgroup.py | 50 | ||||
-rw-r--r-- | tests/utils.py | 2 |
20 files changed, 153 insertions, 26 deletions
diff --git a/openstack/common/log.py b/openstack/common/log.py index d7ba467..d125d90 100644 --- a/openstack/common/log.py +++ b/openstack/common/log.py @@ -43,9 +43,9 @@ import traceback from oslo.config import cfg from openstack.common.gettextutils import _ +from openstack.common import importutils from openstack.common import jsonutils from openstack.common import local -from openstack.common import notifier _DEFAULT_LOG_DATE_FORMAT = "%Y-%m-%d %H:%M:%S" @@ -322,17 +322,6 @@ class JSONFormatter(logging.Formatter): return jsonutils.dumps(message) -class PublishErrorsHandler(logging.Handler): - def emit(self, record): - if ('openstack.common.notifier.log_notifier' in - CONF.notification_driver): - return - notifier.api.notify(None, 'error.publisher', - 'error_notification', - notifier.api.ERROR, - dict(error=record.msg)) - - def _create_logging_excepthook(product_name): def logging_excepthook(type, value, tb): extra = {} @@ -428,7 +417,10 @@ def _setup_logging_from_conf(): log_root.addHandler(streamlog) if CONF.publish_errors: - log_root.addHandler(PublishErrorsHandler(logging.ERROR)) + handler = importutils.import_object( + "openstack.common.log_handler.PublishErrorsHandler", + logging.ERROR) + log_root.addHandler(handler) datefmt = CONF.log_date_format for handler in log_root.handlers: diff --git a/openstack/common/log_handler.py b/openstack/common/log_handler.py new file mode 100644 index 0000000..1f90948 --- /dev/null +++ b/openstack/common/log_handler.py @@ -0,0 +1,31 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 IBM Corp. +# +# 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 logging + +from openstack.common import notifier + +from oslo.config import cfg + + +class PublishErrorsHandler(logging.Handler): + def emit(self, record): + if ('openstack.common.notifier.log_notifier' in + cfg.CONF.notification_driver): + return + notifier.api.notify(None, 'error.publisher', + 'error_notification', + notifier.api.ERROR, + dict(error=record.msg)) diff --git a/openstack/common/periodic_task.py b/openstack/common/periodic_task.py index c48d8b9..4fbb0fe 100644 --- a/openstack/common/periodic_task.py +++ b/openstack/common/periodic_task.py @@ -15,6 +15,7 @@ import datetime import time + from oslo.config import cfg from openstack.common.gettextutils import _ diff --git a/openstack/common/rootwrap/filters.py b/openstack/common/rootwrap/filters.py index 58121cb..ae7c62c 100644 --- a/openstack/common/rootwrap/filters.py +++ b/openstack/common/rootwrap/filters.py @@ -194,6 +194,10 @@ class KillFilter(CommandFilter): return False try: command = os.readlink("/proc/%d/exe" % int(args[1])) + # NOTE(yufang521247): /proc/PID/exe may have '\0' on the + # end, because python doen't stop at '\0' when read the + # target path. + command = command.split('\0')[0] # NOTE(dprince): /proc/PID/exe may have ' (deleted)' on # the end if an executable is updated or deleted if command.endswith(" (deleted)"): diff --git a/openstack/common/rpc/common.py b/openstack/common/rpc/common.py index d74425d..5a7e525 100644 --- a/openstack/common/rpc/common.py +++ b/openstack/common/rpc/common.py @@ -158,6 +158,10 @@ class UnsupportedRpcEnvelopeVersion(RPCException): "not supported by this endpoint.") +class RpcVersionCapError(RPCException): + message = _("Specified RPC version cap, %(version_cap)s, is too low") + + class Connection(object): """A connection, returned by rpc.create_connection(). diff --git a/openstack/common/rpc/proxy.py b/openstack/common/rpc/proxy.py index 284f375..0b311de 100644 --- a/openstack/common/rpc/proxy.py +++ b/openstack/common/rpc/proxy.py @@ -1,6 +1,6 @@ # vim: tabstop=4 shiftwidth=4 softtabstop=4 -# Copyright 2012 Red Hat, Inc. +# Copyright 2012-2013 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 @@ -23,6 +23,7 @@ For more information about rpc API version numbers, see: from openstack.common import rpc +from openstack.common.rpc import common as rpc_common class RpcProxy(object): @@ -34,16 +35,19 @@ class RpcProxy(object): rpc API. """ - def __init__(self, topic, default_version): + def __init__(self, topic, default_version, version_cap=None): """Initialize an RpcProxy. :param topic: The topic to use for all messages. :param default_version: The default API version to request in all outgoing messages. This can be overridden on a per-message basis. + :param version_cap: Optionally cap the maximum version used for sent + messages. """ self.topic = topic self.default_version = default_version + self.version_cap = version_cap super(RpcProxy, self).__init__() def _set_version(self, msg, vers): @@ -52,7 +56,11 @@ class RpcProxy(object): :param msg: The message having a version added to it. :param vers: The version number to add to the message. """ - msg['version'] = vers if vers else self.default_version + v = vers if vers else self.default_version + if (self.version_cap and not + rpc_common.version_is_compatible(self.version_cap, v)): + raise rpc_common.RpcVersionCapError(version=self.version_cap) + msg['version'] = v def _get_topic(self, topic): """Return the topic to use for a message.""" diff --git a/openstack/common/service.py b/openstack/common/service.py index 6ebeefd..eb46164 100644 --- a/openstack/common/service.py +++ b/openstack/common/service.py @@ -52,7 +52,7 @@ class Launcher(object): """ self._services = threadgroup.ThreadGroup() - eventlet_backdoor.initialize_if_enabled() + self.backdoor_port = eventlet_backdoor.initialize_if_enabled() @staticmethod def run_service(service): @@ -72,6 +72,7 @@ class Launcher(object): :returns: None """ + service.backdoor_port = self.backdoor_port self._services.add_thread(self.run_service, service) def stop(self): diff --git a/openstack/common/threadgroup.py b/openstack/common/threadgroup.py index 3558b73..6cafbaf 100644 --- a/openstack/common/threadgroup.py +++ b/openstack/common/threadgroup.py @@ -61,6 +61,13 @@ class ThreadGroup(object): self.threads = [] self.timers = [] + def add_dynamic_timer(self, callback, initial_delay=None, + periodic_interval_max=None, *args, **kwargs): + timer = loopingcall.DynamicLoopingCall(callback, *args, **kwargs) + timer.start(initial_delay=initial_delay, + periodic_interval_max=periodic_interval_max) + self.timers.append(timer) + def add_timer(self, interval, callback, initial_delay=None, *args, **kwargs): pulse = loopingcall.FixedIntervalLoopingCall(callback, *args, **kwargs) diff --git a/tests/unit/db/sqlalchemy/test_sqlalchemy.py b/tests/unit/db/sqlalchemy/test_sqlalchemy.py index efe0264..7cbe31d 100644 --- a/tests/unit/db/sqlalchemy/test_sqlalchemy.py +++ b/tests/unit/db/sqlalchemy/test_sqlalchemy.py @@ -19,8 +19,8 @@ """Unit tests for SQLAlchemy specific code.""" from sqlalchemy import Column, MetaData, Table, UniqueConstraint -from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import DateTime, Integer, String +from sqlalchemy.ext.declarative import declarative_base from openstack.common.db import exception as db_exc from openstack.common.db.sqlalchemy import models diff --git a/tests/unit/rpc/common.py b/tests/unit/rpc/common.py index c4362b2..32f2a9b 100644 --- a/tests/unit/rpc/common.py +++ b/tests/unit/rpc/common.py @@ -19,9 +19,9 @@ Unit Tests for remote procedure calls shared between all implementations """ +import datetime import logging import time -import datetime import eventlet from oslo.config import cfg diff --git a/tests/unit/rpc/test_common.py b/tests/unit/rpc/test_common.py index 1f07ff7..73ca63b 100644 --- a/tests/unit/rpc/test_common.py +++ b/tests/unit/rpc/test_common.py @@ -20,8 +20,8 @@ Unit Tests for 'common' functons used through rpc code. import logging import sys -import six from oslo.config import cfg +import six from openstack.common import exception from openstack.common import importutils diff --git a/tests/unit/rpc/test_kombu.py b/tests/unit/rpc/test_kombu.py index 73ce2ce..ebc29ea 100644 --- a/tests/unit/rpc/test_kombu.py +++ b/tests/unit/rpc/test_kombu.py @@ -26,8 +26,8 @@ import contextlib import logging import mock -import six from oslo.config import cfg +import six from openstack.common import exception from openstack.common.rpc import amqp as rpc_amqp diff --git a/tests/unit/rpc/test_proxy.py b/tests/unit/rpc/test_proxy.py index a84a7ea..63360ba 100644 --- a/tests/unit/rpc/test_proxy.py +++ b/tests/unit/rpc/test_proxy.py @@ -25,8 +25,8 @@ import six from openstack.common import context from openstack.common import lockutils from openstack.common import rpc -from openstack.common.rpc import proxy from openstack.common.rpc import common as rpc_common +from openstack.common.rpc import proxy from tests import utils @@ -85,6 +85,12 @@ class RpcProxyTestCase(utils.BaseTestCase): new_msg['version'] = '1.1' _check_args(ctxt, topic, new_msg) + # override the version to be above a specified cap + rpc_proxy.version_cap = '1.0' + self.assertRaises(rpc_common.RpcVersionCapError, + getattr(rpc_proxy, rpc_method), *args, version='1.1') + rpc_proxy.version_cap = None + if has_timeout: # Set a timeout retval = getattr(rpc_proxy, rpc_method)(ctxt, msg, timeout=42) diff --git a/tests/unit/rpc/test_qpid.py b/tests/unit/rpc/test_qpid.py index 0ee05cf..82cc119 100644 --- a/tests/unit/rpc/test_qpid.py +++ b/tests/unit/rpc/test_qpid.py @@ -29,8 +29,8 @@ from oslo.config import cfg from openstack.common import context from openstack.common.rpc import amqp as rpc_amqp -from tests import utils from openstack.common.rpc import common as rpc_common +from tests import utils try: import qpid diff --git a/tests/unit/test_log.py b/tests/unit/test_log.py index c73f67a..301e3a8 100644 --- a/tests/unit/test_log.py +++ b/tests/unit/test_log.py @@ -10,6 +10,7 @@ from oslo.config import cfg from openstack.common import context from openstack.common import jsonutils from openstack.common import log +from openstack.common.log_handler import PublishErrorsHandler from openstack.common.notifier import api as notifier from tests import utils as test_utils @@ -114,7 +115,7 @@ class PublishErrorsHandlerTestCase(test_utils.BaseTestCase): """Tests for log.PublishErrorsHandler""" def setUp(self): super(PublishErrorsHandlerTestCase, self).setUp() - self.publiserrorshandler = log.PublishErrorsHandler(logging.ERROR) + self.publiserrorshandler = PublishErrorsHandler(logging.ERROR) def test_emit_cfg_log_notifier_in_notifier_drivers(self): self.config(notification_driver=[ diff --git a/tests/unit/test_rootwrap.py b/tests/unit/test_rootwrap.py index ea6ccbb..5a5d9ca 100644 --- a/tests/unit/test_rootwrap.py +++ b/tests/unit/test_rootwrap.py @@ -134,6 +134,18 @@ class RootwrapTestCase(utils.BaseTestCase): self.stubs.Set(os, 'readlink', fake_readlink) self.assertTrue(f.match(usercmd)) + def test_KillFilter_upgraded_exe(self): + """Makes sure upgraded exe's are killed correctly""" + # See bug #1179793. + def fake_readlink(blah): + return '/bin/commandddddd\0\05190bfb2 (deleted)' + + f = filters.KillFilter("root", "/bin/commandddddd") + usercmd = ['kill', 1234] + + self.stubs.Set(os, 'readlink', fake_readlink) + self.assertTrue(f.match(usercmd)) + def test_ReadFileFilter(self): goodfn = '/good/file.name' f = filters.ReadFileFilter(goodfn) diff --git a/tests/unit/test_service.py b/tests/unit/test_service.py index 77cf7ff..b7ba4f7 100644 --- a/tests/unit/test_service.py +++ b/tests/unit/test_service.py @@ -190,3 +190,13 @@ class ServiceLauncherTest(utils.BaseTestCase): status = self._reap_test() self.assertTrue(os.WIFEXITED(status)) self.assertEqual(os.WEXITSTATUS(status), 0) + + +class LauncherTest(utils.BaseTestCase): + def test_backdoor_port(self): + # backdoor port should get passed to the service being launched + self.config(backdoor_port=1234) + svc = service.Service() + launcher = service.launch(svc) + self.assertEqual(1234, svc.backdoor_port) + launcher.stop() diff --git a/tests/unit/test_setup.py b/tests/unit/test_setup.py index c032592..626d71b 100644 --- a/tests/unit/test_setup.py +++ b/tests/unit/test_setup.py @@ -17,8 +17,8 @@ import io import os -import sys import StringIO +import sys from tempfile import mkstemp import fixtures diff --git a/tests/unit/test_threadgroup.py b/tests/unit/test_threadgroup.py new file mode 100644 index 0000000..f627215 --- /dev/null +++ b/tests/unit/test_threadgroup.py @@ -0,0 +1,50 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright (c) 2012 Rackspace Hosting +# 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. + +""" +Unit Tests for thread groups +""" + +from openstack.common import log as logging +from openstack.common import threadgroup +from tests import utils + +LOG = logging.getLogger(__name__) + + +class ThreadGroupTestCase(utils.BaseTestCase): + """Test cases for thread group""" + def setUp(self): + super(ThreadGroupTestCase, self).setUp() + self.tg = threadgroup.ThreadGroup() + self.addCleanup(self.tg.stop) + + def test_add_dynamic_timer(self): + + def foo(*args, **kwargs): + pass + initial_delay = 1 + periodic_interval_max = 2 + self.tg.add_dynamic_timer(foo, initial_delay, periodic_interval_max, + 'arg', kwarg='kwarg') + + self.assertEqual(1, len(self.tg.timers)) + + timer = self.tg.timers[0] + self.assertTrue(timer._running) + self.assertEqual(('arg',), timer.args) + self.assertEqual({'kwarg': 'kwarg'}, timer.kw) diff --git a/tests/utils.py b/tests/utils.py index 591ebef..c5c7c00 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -21,8 +21,8 @@ import fixtures from oslo.config import cfg import testtools -from openstack.common.fixture import moxstubout from openstack.common import exception +from openstack.common.fixture import moxstubout CONF = cfg.CONF |