From 17daedc6cc482111e20e0ec1f884b851a08e953b Mon Sep 17 00:00:00 2001 From: Alessio Ababilov Date: Wed, 13 Feb 2013 16:34:34 +0200 Subject: [PATCH] Synchronize code from oslo Use commit eaab5fae2502198e9fa57d0d90a7204a2bd83b16: Merge "sort options to make --help output prettier" (Wed Feb 13 12:52:14 2013 +0000). Changes: 9669767 Fix PEP8 error in oslo-rootwrap e3e5e0e Fixes "is not", "not in" syntax usage d156150 Implements import_group 0ce65aa sort options to make --help output prettier 580c259 Make tox run doctests d8c4e0c Change Exception MissingArgs's string 6d102bc Provide i18n to those messages without _() cf705c5 Make project pyflakes clean 9e5912f Fix pep8 E125 errors 4a1ec21 Support testing args for LocalhostMatchMaker 9fd6437 Exchanges should return directed topics a4b6c31 Allow running test in uninstalled source tree 1461135 timeutils: considers that now is soon a956f7a Import timeutils.is_soon from keystoneclient a4b6c31 Allow running test in uninstalled source tree 076e9e5 Add support for directly stringifying VersionInfo Change-Id: I427508f0882a528d040c89290ff9ca68a1e91bcd Fixes: bug #1124213 --- bin/nova-rootwrap | 17 ++++++----- nova/openstack/__init__.py | 15 ---------- nova/openstack/common/__init__.py | 15 ---------- nova/openstack/common/cfg.py | 30 +++++++++++++++---- nova/openstack/common/cliutils.py | 13 ++++---- nova/openstack/common/excutils.py | 6 ++-- nova/openstack/common/plugin/pluginmanager.py | 1 + nova/openstack/common/policy.py | 20 ++++++------- nova/openstack/common/rpc/impl_zmq.py | 5 ++-- nova/openstack/common/rpc/matchmaker.py | 17 ++++++----- nova/openstack/common/setup.py | 8 ++--- nova/openstack/common/timeutils.py | 18 +++++++++++ nova/openstack/common/version.py | 14 +++++++-- 13 files changed, 99 insertions(+), 80 deletions(-) diff --git a/bin/nova-rootwrap b/bin/nova-rootwrap index 72a8c6309950..35e2f47f3964 100755 --- a/bin/nova-rootwrap +++ b/bin/nova-rootwrap @@ -20,14 +20,17 @@ Filters which commands a service is allowed to run as another user. - To use this with nova, you should set the following in nova.conf: + To use this with nova, you should set the following in + nova.conf: rootwrap_config=/etc/nova/rootwrap.conf - You also need to let the nova user run nova-rootwrap as root in sudoers: - nova ALL = (root) NOPASSWD: /usr/bin/nova-rootwrap /etc/nova/rootwrap.conf * + You also need to let the nova user run nova-rootwrap + as root in sudoers: + nova ALL = (root) NOPASSWD: /usr/bin/nova-rootwrap + /etc/nova/rootwrap.conf * - Service packaging should deploy .filters files only on nodes where they are - needed, to avoid allowing more than is necessary. + Service packaging should deploy .filters files only on nodes where + they are needed, to avoid allowing more than is necessary. """ import ConfigParser @@ -102,8 +105,8 @@ if __name__ == '__main__': exec_dirs=config.exec_dirs) if config.use_syslog: logging.info("(%s > %s) Executing %s (filter match = %s)" % ( - os.getlogin(), pwd.getpwuid(os.getuid())[0], - command, filtermatch.name)) + os.getlogin(), pwd.getpwuid(os.getuid())[0], + command, filtermatch.name)) obj = subprocess.Popen(command, stdin=sys.stdin, diff --git a/nova/openstack/__init__.py b/nova/openstack/__init__.py index 0a3b98867a26..e69de29bb2d1 100644 --- a/nova/openstack/__init__.py +++ b/nova/openstack/__init__.py @@ -1,15 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright (c) 2011 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. diff --git a/nova/openstack/common/__init__.py b/nova/openstack/common/__init__.py index 0a3b98867a26..e69de29bb2d1 100644 --- a/nova/openstack/common/__init__.py +++ b/nova/openstack/common/__init__.py @@ -1,15 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright (c) 2011 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. diff --git a/nova/openstack/common/cfg.py b/nova/openstack/common/cfg.py index 534a610c0694..baecc0c3b8dd 100644 --- a/nova/openstack/common/cfg.py +++ b/nova/openstack/common/cfg.py @@ -863,7 +863,7 @@ class SubCommandOpt(Opt): description=self.description, help=self.help) - if not self.handler is None: + if self.handler is not None: self.handler(subparsers) @@ -1297,6 +1297,24 @@ class ConfigOpts(collections.Mapping): __import__(module_str) self._get_opt_info(name, group) + def import_group(self, group, module_str): + """Import an option group from a module. + + Import a module and check that a given option group is registered. + + This is intended for use with global configuration objects + like cfg.CONF where modules commonly register options with + CONF at module load time. If one module requires an option group + defined by another module it can use this method to explicitly + declare the dependency. + + :param group: an option OptGroup object or group name + :param module_str: the name of a module to import + :raises: ImportError, NoSuchGroupError + """ + __import__(module_str) + self._get_group(group) + @__clear_cache def set_override(self, name, override, group=None): """Override an opt value. @@ -1547,8 +1565,8 @@ class ConfigOpts(collections.Mapping): group = group_or_name if isinstance(group_or_name, OptGroup) else None group_name = group.name if group else group_or_name - if not group_name in self._groups: - if not group is None or not autocreate: + if group_name not in self._groups: + if group is not None or not autocreate: raise NoSuchGroupError(group_name) self.register_group(OptGroup(name=group_name)) @@ -1568,7 +1586,7 @@ class ConfigOpts(collections.Mapping): group = self._get_group(group) opts = group._opts - if not opt_name in opts: + if opt_name not in opts: raise NoSuchOptError(opt_name, group) return opts[opt_name] @@ -1606,7 +1624,7 @@ class ConfigOpts(collections.Mapping): opt = info['opt'] if opt.required: - if ('default' in info or 'override' in info): + if 'default' in info or 'override' in info: continue if self._get(opt.dest, group) is None: @@ -1625,7 +1643,7 @@ class ConfigOpts(collections.Mapping): """ self._args = args - for opt, group in self._all_cli_opts(): + for opt, group in sorted(self._all_cli_opts()): opt._add_to_cli(self._oparser, group) return vars(self._oparser.parse_args(args)) diff --git a/nova/openstack/common/cliutils.py b/nova/openstack/common/cliutils.py index 8f4dc44dd995..411bd58f3756 100644 --- a/nova/openstack/common/cliutils.py +++ b/nova/openstack/common/cliutils.py @@ -15,7 +15,6 @@ # under the License. import inspect -import string class MissingArgs(Exception): @@ -25,12 +24,10 @@ class MissingArgs(Exception): def __str__(self): if len(self.missing) == 1: - return ("An argument is missing: %(missing)s" % - dict(missing=self.missing[0])) + return "An argument is missing" else: - return ("%(num)d arguments are missing: %(missing)s" % - dict(num=len(self.missing), - missing=string.join(self.missing, ', '))) + return ("%(num)d arguments are missing" % + dict(num=len(self.missing))) def validate_args(fn, *args, **kwargs): @@ -39,11 +36,11 @@ def validate_args(fn, *args, **kwargs): >>> validate_args(lambda a: None) Traceback (most recent call last): ... - MissingArgs: An argument is missing: a + MissingArgs: An argument is missing >>> validate_args(lambda a, b, c, d: None, 0, c=1) Traceback (most recent call last): ... - MissingArgs: 2 arguments are missing: b, d + MissingArgs: 2 arguments are missing :param fn: the function to check :param arg: the positional arguments supplied diff --git a/nova/openstack/common/excutils.py b/nova/openstack/common/excutils.py index 5dd48301760e..e507efceda80 100644 --- a/nova/openstack/common/excutils.py +++ b/nova/openstack/common/excutils.py @@ -24,6 +24,8 @@ import logging import sys import traceback +from nova.openstack.common.gettextutils import _ + @contextlib.contextmanager def save_and_reraise_exception(): @@ -43,7 +45,7 @@ def save_and_reraise_exception(): try: yield except Exception: - logging.error('Original exception being dropped: %s' % - (traceback.format_exception(type_, value, tb))) + logging.error(_('Original exception being dropped: %s'), + traceback.format_exception(type_, value, tb)) raise raise type_, value, tb diff --git a/nova/openstack/common/plugin/pluginmanager.py b/nova/openstack/common/plugin/pluginmanager.py index 51d06d851a6b..157ecbf445c2 100644 --- a/nova/openstack/common/plugin/pluginmanager.py +++ b/nova/openstack/common/plugin/pluginmanager.py @@ -16,6 +16,7 @@ import pkg_resources from nova.openstack.common import cfg +from nova.openstack.common.gettextutils import _ from nova.openstack.common import log as logging from nova.openstack.common.notifier import api as notifier_api diff --git a/nova/openstack/common/policy.py b/nova/openstack/common/policy.py index 496ed972db66..626a61aa50a3 100644 --- a/nova/openstack/common/policy.py +++ b/nova/openstack/common/policy.py @@ -574,19 +574,19 @@ class ParseState(object): for reduction, methname in self.reducers: if (len(self.tokens) >= len(reduction) and - self.tokens[-len(reduction):] == reduction): - # Get the reduction method - meth = getattr(self, methname) + self.tokens[-len(reduction):] == reduction): + # Get the reduction method + meth = getattr(self, methname) - # Reduce the token stream - results = meth(*self.values[-len(reduction):]) + # Reduce the token stream + results = meth(*self.values[-len(reduction):]) - # Update the tokens and values - self.tokens[-len(reduction):] = [r[0] for r in results] - self.values[-len(reduction):] = [r[1] for r in results] + # Update the tokens and values + self.tokens[-len(reduction):] = [r[0] for r in results] + self.values[-len(reduction):] = [r[1] for r in results] - # Check for any more reductions - return self.reduce() + # Check for any more reductions + return self.reduce() def shift(self, tok, value): """Adds one more token to the state. Calls reduce().""" diff --git a/nova/openstack/common/rpc/impl_zmq.py b/nova/openstack/common/rpc/impl_zmq.py index 2c06315481ed..d562b932ff68 100644 --- a/nova/openstack/common/rpc/impl_zmq.py +++ b/nova/openstack/common/rpc/impl_zmq.py @@ -772,8 +772,9 @@ def _get_ctxt(): return ZMQ_CTX -def _get_matchmaker(): +def _get_matchmaker(*args, **kwargs): global matchmaker if not matchmaker: - matchmaker = importutils.import_object(CONF.rpc_zmq_matchmaker) + matchmaker = importutils.import_object( + CONF.rpc_zmq_matchmaker, *args, **kwargs) return matchmaker diff --git a/nova/openstack/common/rpc/matchmaker.py b/nova/openstack/common/rpc/matchmaker.py index 8b2c67a44785..9eec1df83c04 100644 --- a/nova/openstack/common/rpc/matchmaker.py +++ b/nova/openstack/common/rpc/matchmaker.py @@ -201,24 +201,25 @@ class FanoutRingExchange(RingExchange): class LocalhostExchange(Exchange): """Exchange where all direct topics are local.""" - def __init__(self): + def __init__(self, host='localhost'): + self.host = host super(Exchange, self).__init__() def run(self, key): - return [(key.split('.')[0] + '.localhost', 'localhost')] + return [('.'.join((key.split('.')[0], self.host)), self.host)] class DirectExchange(Exchange): """ Exchange where all topic keys are split, sending to second half. - i.e. "compute.host" sends a message to "compute" running on "host" + i.e. "compute.host" sends a message to "compute.host" running on "host" """ def __init__(self): super(Exchange, self).__init__() def run(self, key): - b, e = key.split('.', 1) - return [(b, e)] + e = key.split('.', 1)[1] + return [(key, e)] class MatchMakerRing(MatchMakerBase): @@ -237,11 +238,11 @@ class MatchMakerLocalhost(MatchMakerBase): Match Maker where all bare topics resolve to localhost. Useful for testing. """ - def __init__(self): + def __init__(self, host='localhost'): super(MatchMakerLocalhost, self).__init__() - self.add_binding(FanoutBinding(), LocalhostExchange()) + self.add_binding(FanoutBinding(), LocalhostExchange(host)) self.add_binding(DirectBinding(), DirectExchange()) - self.add_binding(TopicBinding(), LocalhostExchange()) + self.add_binding(TopicBinding(), LocalhostExchange(host)) class MatchMakerStub(MatchMakerBase): diff --git a/nova/openstack/common/setup.py b/nova/openstack/common/setup.py index fb187fff4654..35680b30485b 100644 --- a/nova/openstack/common/setup.py +++ b/nova/openstack/common/setup.py @@ -274,7 +274,7 @@ def _get_revno(): return len(revlist.splitlines()) -def get_version_from_git(pre_version): +def _get_version_from_git(pre_version): """Return a version which is equal to the tag that's on the current revision if there is one, or tag plus number of additional revisions if the current revision has no tag.""" @@ -294,7 +294,7 @@ def get_version_from_git(pre_version): return None -def get_version_from_pkg_info(package_name): +def _get_version_from_pkg_info(package_name): """Get the version from PKG-INFO file if we can.""" try: pkg_info_file = open('PKG-INFO', 'r') @@ -325,10 +325,10 @@ def get_version(package_name, pre_version=None): version = os.environ.get("OSLO_PACKAGE_VERSION", None) if version: return version - version = get_version_from_pkg_info(package_name) + version = _get_version_from_pkg_info(package_name) if version: return version - version = get_version_from_git(pre_version) + version = _get_version_from_git(pre_version) if version: return version raise Exception("Versioning for this project requires either an sdist" diff --git a/nova/openstack/common/timeutils.py b/nova/openstack/common/timeutils.py index 0f346087f78d..e2c274057312 100644 --- a/nova/openstack/common/timeutils.py +++ b/nova/openstack/common/timeutils.py @@ -98,6 +98,11 @@ def utcnow(): return datetime.datetime.utcnow() +def iso8601_from_timestamp(timestamp): + """Returns a iso8601 formated date from timestamp""" + return isotime(datetime.datetime.utcfromtimestamp(timestamp)) + + utcnow.override_time = None @@ -162,3 +167,16 @@ def delta_seconds(before, after): except AttributeError: return ((delta.days * 24 * 3600) + delta.seconds + float(delta.microseconds) / (10 ** 6)) + + +def is_soon(dt, window): + """ + Determines if time is going to happen in the next window seconds. + + :params dt: the time + :params window: minimum seconds to remain to consider the time not soon + + :return: True if expiration is within the given duration + """ + soon = (utcnow() + datetime.timedelta(seconds=window)) + return normalize_time(dt) <= soon diff --git a/nova/openstack/common/version.py b/nova/openstack/common/version.py index b16ef4bca0ae..57803b3d5db3 100644 --- a/nova/openstack/common/version.py +++ b/nova/openstack/common/version.py @@ -33,6 +33,14 @@ class VersionInfo(object): self.version = None self._cached_version = None + def __str__(self): + """Make the VersionInfo object behave like a string.""" + return self.version_string() + + def __repr__(self): + """Include the name.""" + return "VersionInfo(%s:%s)" % (self.package, self.version_string()) + def _get_version_from_pkg_resources(self): """Get the version of the package from the pkg_resources record associated with the package.""" @@ -41,11 +49,11 @@ class VersionInfo(object): provider = pkg_resources.get_provider(requirement) return provider.version except pkg_resources.DistributionNotFound: - # The most likely cause for this is running tests in a tree with + # The most likely cause for this is running tests in a tree # produced from a tarball where the package itself has not been - # installed into anything. Check for a PKG-INFO file. + # installed into anything. Revert to setup-time logic. from nova.openstack.common import setup - return setup.get_version_from_pkg_info(self.package) + return setup.get_version(self.package) def release_string(self): """Return the full version of the package including suffixes indicating