]> review.fuel-infra Code Review - openstack-build/heat-build.git/commitdiff
Merge from Oslo-incubator
authorDirk Mueller <dirk@dmllr.de>
Mon, 28 Jan 2013 17:06:55 +0000 (18:06 +0100)
committerDirk Mueller <dirk@dmllr.de>
Mon, 28 Jan 2013 17:18:57 +0000 (18:18 +0100)
Change-Id: I2ef3bb9acdfb5bcae574d812e06fd689d0a7c890

doc/source/conf.py
heat/openstack/common/cfg.py
heat/openstack/common/log.py
heat/openstack/common/notifier/rpc_notifier2.py [new file with mode: 0644]
heat/openstack/common/rpc/impl_zmq.py
heat/openstack/common/setup.py
heat/openstack/common/timeutils.py
heat/openstack/common/version.py

index 87a91e44e0ecf1bf6e2c1e1203fb49b00a5ac8aa..5ed01cf6d2c337fbd57a47879dd99613727d82e5 100644 (file)
@@ -51,8 +51,10 @@ copyright = u'2012, Heat Developers'
 # |version| and |release|, also used in various other places throughout the
 # built documents.
 
-from heat.version import version_info as heat_version
-release = heat_version.version_string_with_vcs()
+from heat import version as heat_version
+# The full version, including alpha/beta/rc tags.
+release = heat_version.version_string()
+# The short X.Y version
 version = heat_version.canonical_version_string()
 
 # The language for content autogenerated by Sphinx. Refer to documentation
index 07f9914755fd8ecc61ed410daa417fe113158eac..349a6ae279b66380e35d13140fe320af03cfb322 100644 (file)
@@ -217,7 +217,7 @@ log files::
         ...
      ]
 
-This module also contains a global instance of the CommonConfigOpts class
+This module also contains a global instance of the ConfigOpts class
 in order to support a common usage pattern in OpenStack::
 
     from heat.openstack.common import cfg
@@ -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)
 
 
@@ -1547,8 +1547,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 +1568,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 +1606,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:
@@ -1728,64 +1728,4 @@ class ConfigOpts(collections.Mapping):
             return value
 
 
-class CommonConfigOpts(ConfigOpts):
-
-    DEFAULT_LOG_FORMAT = "%(asctime)s %(levelname)8s [%(name)s] %(message)s"
-    DEFAULT_LOG_DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
-
-    common_cli_opts = [
-        BoolOpt('debug',
-                short='d',
-                default=False,
-                help='Print debugging output (set logging level to '
-                     'DEBUG instead of default WARNING level).'),
-        BoolOpt('verbose',
-                short='v',
-                default=False,
-                help='Print more verbose output (set logging level to '
-                     'INFO instead of default WARNING level).'),
-    ]
-
-    logging_cli_opts = [
-        StrOpt('log-config',
-               metavar='PATH',
-               help='If this option is specified, the logging configuration '
-                    'file specified is used and overrides any other logging '
-                    'options specified. Please see the Python logging module '
-                    'documentation for details on logging configuration '
-                    'files.'),
-        StrOpt('log-format',
-               default=DEFAULT_LOG_FORMAT,
-               metavar='FORMAT',
-               help='A logging.Formatter log message format string which may '
-                    'use any of the available logging.LogRecord attributes. '
-                    'Default: %(default)s'),
-        StrOpt('log-date-format',
-               default=DEFAULT_LOG_DATE_FORMAT,
-               metavar='DATE_FORMAT',
-               help='Format string for %%(asctime)s in log records. '
-                    'Default: %(default)s'),
-        StrOpt('log-file',
-               metavar='PATH',
-               deprecated_name='logfile',
-               help='(Optional) Name of log file to output to. '
-                    'If not set, logging will go to stdout.'),
-        StrOpt('log-dir',
-               deprecated_name='logdir',
-               help='(Optional) The directory to keep log files in '
-                    '(will be prepended to --log-file)'),
-        BoolOpt('use-syslog',
-                default=False,
-                help='Use syslog for logging.'),
-        StrOpt('syslog-log-facility',
-               default='LOG_USER',
-               help='syslog facility to receive log lines')
-    ]
-
-    def __init__(self):
-        super(CommonConfigOpts, self).__init__()
-        self.register_cli_opts(self.common_cli_opts)
-        self.register_cli_opts(self.logging_cli_opts)
-
-
-CONF = CommonConfigOpts()
+CONF = ConfigOpts()
index 50adedbbc362351cd2c26a8e7ceefcb132dd906d..9c2a9a0c49be43e66e49eaaecfbabe54753aa040 100644 (file)
@@ -47,6 +47,67 @@ from heat.openstack.common import local
 from heat.openstack.common import notifier
 
 
+_DEFAULT_LOG_FORMAT = "%(asctime)s %(levelname)8s [%(name)s] %(message)s"
+_DEFAULT_LOG_DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
+
+common_cli_opts = [
+    cfg.BoolOpt('debug',
+                short='d',
+                default=False,
+                help='Print debugging output (set logging level to '
+                     'DEBUG instead of default WARNING level).'),
+    cfg.BoolOpt('verbose',
+                short='v',
+                default=False,
+                help='Print more verbose output (set logging level to '
+                     'INFO instead of default WARNING level).'),
+]
+
+logging_cli_opts = [
+    cfg.StrOpt('log-config',
+               metavar='PATH',
+               help='If this option is specified, the logging configuration '
+                    'file specified is used and overrides any other logging '
+                    'options specified. Please see the Python logging module '
+                    'documentation for details on logging configuration '
+                    'files.'),
+    cfg.StrOpt('log-format',
+               default=_DEFAULT_LOG_FORMAT,
+               metavar='FORMAT',
+               help='A logging.Formatter log message format string which may '
+                    'use any of the available logging.LogRecord attributes. '
+                    'Default: %(default)s'),
+    cfg.StrOpt('log-date-format',
+               default=_DEFAULT_LOG_DATE_FORMAT,
+               metavar='DATE_FORMAT',
+               help='Format string for %%(asctime)s in log records. '
+                    'Default: %(default)s'),
+    cfg.StrOpt('log-file',
+               metavar='PATH',
+               deprecated_name='logfile',
+               help='(Optional) Name of log file to output to. '
+                    'If not set, logging will go to stdout.'),
+    cfg.StrOpt('log-dir',
+               deprecated_name='logdir',
+               help='(Optional) The directory to keep log files in '
+                    '(will be prepended to --log-file)'),
+    cfg.BoolOpt('use-syslog',
+                default=False,
+                help='Use syslog for logging.'),
+    cfg.StrOpt('syslog-log-facility',
+               default='LOG_USER',
+               help='syslog facility to receive log lines')
+]
+
+generic_log_opts = [
+    cfg.BoolOpt('use_stderr',
+                default=True,
+                help='Log output to standard error'),
+    cfg.StrOpt('logfile_mode',
+               default='0644',
+               help='Default file mode used when creating log files'),
+]
+
 log_opts = [
     cfg.StrOpt('logging_context_format_string',
                default='%(asctime)s.%(msecs)03d %(levelname)s %(name)s '
@@ -94,24 +155,9 @@ log_opts = [
                     'format it like this'),
 ]
 
-
-generic_log_opts = [
-    cfg.StrOpt('logdir',
-               default=None,
-               help='Log output to a per-service log file in named directory'),
-    cfg.StrOpt('logfile',
-               default=None,
-               help='Log output to a named file'),
-    cfg.BoolOpt('use_stderr',
-                default=True,
-                help='Log output to standard error'),
-    cfg.StrOpt('logfile_mode',
-               default='0644',
-               help='Default file mode used when creating log files'),
-]
-
-
 CONF = cfg.CONF
+CONF.register_cli_opts(common_cli_opts)
+CONF.register_cli_opts(logging_cli_opts)
 CONF.register_opts(generic_log_opts)
 CONF.register_opts(log_opts)
 
@@ -149,8 +195,8 @@ def _get_binary_name():
 
 
 def _get_log_file_path(binary=None):
-    logfile = CONF.log_file or CONF.logfile
-    logdir = CONF.log_dir or CONF.logdir
+    logfile = CONF.log_file
+    logdir = CONF.log_dir
 
     if logfile and not logdir:
         return logfile
diff --git a/heat/openstack/common/notifier/rpc_notifier2.py b/heat/openstack/common/notifier/rpc_notifier2.py
new file mode 100644 (file)
index 0000000..e38663e
--- /dev/null
@@ -0,0 +1,51 @@
+# Copyright 2011 OpenStack LLC.
+# 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.
+
+'''messaging based notification driver, with message envelopes'''
+
+from heat.openstack.common import cfg
+from heat.openstack.common import context as req_context
+from heat.openstack.common.gettextutils import _
+from heat.openstack.common import log as logging
+from heat.openstack.common import rpc
+
+LOG = logging.getLogger(__name__)
+
+notification_topic_opt = cfg.ListOpt(
+    'topics', default=['notifications', ],
+    help='AMQP topic(s) used for openstack notifications')
+
+opt_group = cfg.OptGroup(name='rpc_notifier2',
+                         title='Options for rpc_notifier2')
+
+CONF = cfg.CONF
+CONF.register_group(opt_group)
+CONF.register_opt(notification_topic_opt, opt_group)
+
+
+def notify(context, message):
+    """Sends a notification via RPC"""
+    if not context:
+        context = req_context.get_admin_context()
+    priority = message.get('priority',
+                           CONF.default_notification_level)
+    priority = priority.lower()
+    for topic in CONF.rpc_notifier2.topics:
+        topic = '%s.%s' % (topic, priority)
+        try:
+            rpc.notify(context, topic, message, envelope=True)
+        except Exception:
+            LOG.exception(_("Could not send notification to %(topic)s. "
+                            "Payload=%(message)s"), locals())
index b2c16bfcf237b792b04d045962430c95f1d363a6..1e10fbf04c859aea1440561bf37d07aba0f5534f 100644 (file)
@@ -449,7 +449,7 @@ class ZmqProxy(ZmqBaseReactor):
         else:
             sock_type = zmq.PUSH
 
-        if not topic in self.topic_proxy:
+        if topic not in self.topic_proxy:
             def publisher(waiter):
                 LOG.info(_("Creating proxy for topic: %s"), topic)
 
index 7267a6a27fc24929d0b2e2eaec84305d7007bbc0..fb187fff465424ee7b677c8ed86c4aa01bf4eec8 100644 (file)
@@ -108,13 +108,17 @@ def parse_dependency_links(requirements_files=['requirements.txt',
     return dependency_links
 
 
-def _run_shell_command(cmd):
+def _run_shell_command(cmd, throw_on_error=False):
     if os.name == 'nt':
         output = subprocess.Popen(["cmd.exe", "/C", cmd],
-                                  stdout=subprocess.PIPE)
+                                  stdout=subprocess.PIPE,
+                                  stderr=subprocess.PIPE)
     else:
         output = subprocess.Popen(["/bin/sh", "-c", cmd],
-                                  stdout=subprocess.PIPE)
+                                  stdout=subprocess.PIPE,
+                                  stderr=subprocess.PIPE)
+    if output.returncode and throw_on_error:
+        raise Exception("%s returned %d" % cmd, output.returncode)
     out = output.communicate()
     if len(out) == 0:
         return None
@@ -254,14 +258,39 @@ def get_cmdclass():
     return cmdclass
 
 
-def get_version_from_git():
+def _get_revno():
+    """Return the number of commits since the most recent tag.
+
+    We use git-describe to find this out, but if there are no
+    tags then we fall back to counting commits since the beginning
+    of time.
+    """
+    describe = _run_shell_command("git describe --always")
+    if "-" in describe:
+        return describe.rsplit("-", 2)[-2]
+
+    # no tags found
+    revlist = _run_shell_command("git rev-list --abbrev-commit HEAD")
+    return len(revlist.splitlines())
+
+
+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."""
 
     if os.path.isdir('.git'):
-        return _run_shell_command(
-            "git describe --always").replace('-', '.')
+        if pre_version:
+            try:
+                return _run_shell_command(
+                    "git describe --exact-match",
+                    throw_on_error=True).replace('-', '.')
+            except Exception:
+                sha = _run_shell_command("git log -n1 --pretty=format:%h")
+                return "%s.a%s.g%s" % (pre_version, _get_revno(), sha)
+        else:
+            return _run_shell_command(
+                "git describe --always").replace('-', '.')
     return None
 
 
@@ -281,7 +310,7 @@ def get_version_from_pkg_info(package_name):
     return pkg_info.get('Version', None)
 
 
-def get_version(package_name):
+def get_version(package_name, pre_version=None):
     """Get the version of the project. First, try getting it from PKG-INFO, if
     it exists. If it does, that means we're in a distribution tarball or that
     install has happened. Otherwise, if there is no PKG-INFO file, pull the
@@ -293,10 +322,13 @@ def get_version(package_name):
     to make a source tarball from a fork of our repo with additional tags in it
     that they understand and desire the results of doing that.
     """
+    version = os.environ.get("OSLO_PACKAGE_VERSION", None)
+    if version:
+        return version
     version = get_version_from_pkg_info(package_name)
     if version:
         return version
-    version = get_version_from_git()
+    version = get_version_from_git(pre_version)
     if version:
         return version
     raise Exception("Versioning for this project requires either an sdist"
index 0f346087f78dbeae8f329efbfc9731c155f2d8ad..5a011e8181fe9f3e6b42504acb26478d2dc8e1f3 100644 (file)
@@ -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
index 8f7e1a900253671f6040e12aaf1d78153233c815..3653ad0d0e68657362741f4f2549beac16371f0b 100644 (file)
@@ -29,6 +29,7 @@ class VersionInfo(object):
                         python-glanceclient
         """
         self.package = package
+        self.release = None
         self.version = None
         self._cached_version = None
 
@@ -39,18 +40,31 @@ class VersionInfo(object):
         provider = pkg_resources.get_provider(requirement)
         return provider.version
 
-    def version_string(self):
+    def release_string(self):
         """Return the full version of the package including suffixes indicating
         VCS status.
         """
+        if self.release is None:
+            self.release = self._get_version_from_pkg_resources()
+
+        return self.release
+
+    def version_string(self):
+        """Return the short version minus any alpha/beta tags."""
         if self.version is None:
-            self.version = self._get_version_from_pkg_resources()
+            parts = []
+            for part in self.release_string().split('.'):
+                if part[0].isdigit():
+                    parts.append(part)
+                else:
+                    break
+            self.version = ".".join(parts)
 
         return self.version
 
     # Compatibility functions
     canonical_version_string = version_string
-    version_string_with_vcs = version_string
+    version_string_with_vcs = release_string
 
     def cached_version_string(self, prefix=""):
         """Generate an object which will expand in a string context to