rally/rally/utils.py
Christian Berendt fa99d1a314 replaced e.message
BaseException.message has been deprecated as of Python 2.6.

http://legacy.python.org/dev/peps/pep-0352/

Replaced e.message with six.text_type(e) (uses unicode with
Python 2.x and str with Python 3.x).

Change-Id: I8d0c43f9383cec343ca159061b7a93d3db45a74a
2014-05-16 18:19:38 +02:00

196 lines
5.9 KiB
Python

# Copyright 2013: Mirantis Inc.
# 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.
import functools
import imp
import itertools
import os
import StringIO
import sys
import time
import six
from rally import exceptions
from rally.openstack.common.gettextutils import _
from rally.openstack.common import importutils
from rally.openstack.common import log as logging
LOG = logging.getLogger(__name__)
JSON_SCHEMA = 'http://json-schema.org/draft-04/schema'
class ImmutableMixin(object):
_inited = False
def __init__(self):
self._inited = True
def __setattr__(self, key, value):
if self._inited:
raise exceptions.ImmutableException()
super(ImmutableMixin, self).__setattr__(key, value)
class EnumMixin(object):
def __iter__(self):
for k, v in itertools.imap(lambda x: (x, getattr(self, x)), dir(self)):
if not k.startswith('_'):
yield v
class StdOutCapture(object):
def __init__(self):
self.stdout = sys.stdout
def __enter__(self):
sys.stdout = StringIO.StringIO()
return sys.stdout
def __exit__(self, type, value, traceback):
sys.stdout = self.stdout
class StdErrCapture(object):
def __init__(self):
self.stderr = sys.stderr
def __enter__(self):
sys.stderr = StringIO.StringIO()
return sys.stderr
def __exit__(self, type, value, traceback):
sys.stderr = self.stderr
class Timer(object):
def __enter__(self):
self.error = None
self.start = time.time()
return self
def __exit__(self, type, value, tb):
self.finish = time.time()
if type:
self.error = (type, value, tb)
def duration(self):
return self.finish - self.start
class Struct(object):
def __init__(self, **entries):
self.__dict__.update(entries)
def itersubclasses(cls, _seen=None):
"""Generator over all subclasses of a given class in depth first order."""
if not isinstance(cls, type):
raise TypeError(_('itersubclasses must be called with '
'new-style classes, not %.100r') % cls)
_seen = _seen or set()
try:
subs = cls.__subclasses__()
except TypeError: # fails only when cls is type
subs = cls.__subclasses__(cls)
for sub in subs:
if sub not in _seen:
_seen.add(sub)
yield sub
for sub in itersubclasses(sub, _seen):
yield sub
def try_append_module(name, modules):
if name not in modules:
modules[name] = importutils.import_module(name)
def import_modules_from_package(package):
"""Import modules from package and append into sys.modules
:param: package - Full package name. For example: rally.deploy.engines
"""
path = [os.path.dirname(__file__), '..'] + package.split('.')
path = os.path.join(*path)
for root, dirs, files in os.walk(path):
for filename in files:
if filename.startswith('__') or not filename.endswith('.py'):
continue
new_package = ".".join(root.split(os.sep)).split("....")[1]
module_name = '%s.%s' % (new_package, filename[:-3])
try_append_module(module_name, sys.modules)
def _log_wrapper(obj, log, msg, **kw):
"""A logging wrapper for any method of a class.
Class instances that use this decorator should have self.task or
self.deployment attribute. The wrapper produces logs messages both
before and after the method execution, in the following format
(example for tasks):
"Task <Task UUID> | Starting: <Logging message>"
[Method execution...]
"Task <Task UUID> | Completed: <Logging message>"
:param obj: task or deployment which must be attribute of 'self'
:param log: Logging method to be used, e.g. LOG.info
:param msg: Text message (possibly parameterized) to be put to the log
:param **kw: Parameters for msg
"""
def decorator(f):
@functools.wraps(f)
def wrapper(self, *args, **kwargs):
params = {"msg": msg % kw, "obj_name": obj.title(),
"uuid": getattr(self, obj)["uuid"]}
log(_("%(obj_name)s %(uuid)s | Starting: %(msg)s") % params)
result = f(self, *args, **kwargs)
log(_("%(obj_name)s %(uuid)s | Completed: %(msg)s") % params)
return result
return wrapper
return decorator
def log_task_wrapper(log, msg, **kw):
return _log_wrapper('task', log, msg, **kw)
def log_deploy_wrapper(log, msg, **kw):
return _log_wrapper('deployment', log, msg, **kw)
def log_verification_wrapper(log, msg, **kw):
return _log_wrapper('verification', log, msg, **kw)
def load_plugins(directory):
if os.path.exists(directory):
plugins = (pl[:-3] for pl in os.listdir(directory)
if pl.endswith(".py") and
os.path.isfile(os.path.join(directory, pl)))
for plugin in plugins:
fullpath = os.path.join(directory, plugin)
try:
fp, pathname, descr = imp.find_module(plugin, [directory])
imp.load_module(plugin, fp, pathname, descr)
fp.close()
LOG.debug("Load plugin from file %s" % fullpath)
except Exception as e:
LOG.error(_("Couldn't load module from %(path)s: %(msg)s") %
{"path": fullpath, "msg": six.text_type(e)})