Removing ThreadGroupExecutor allows to get rid of threading2 dependency. LastFedIter is also not used, so there is no reason to keep it. Change-Id: Id396ab59ebf1e2314ef620417d7cac09e1ab8d3b
		
			
				
	
	
		
			186 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			186 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
# -*- coding: utf-8 -*-
 | 
						|
 | 
						|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 | 
						|
 | 
						|
#    Copyright (C) 2012 Yahoo! Inc. All Rights Reserved.
 | 
						|
#    Copyright (C) 2013 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.
 | 
						|
 | 
						|
from distutils import version
 | 
						|
 | 
						|
import collections
 | 
						|
import copy
 | 
						|
import logging
 | 
						|
import six
 | 
						|
import sys
 | 
						|
 | 
						|
LOG = logging.getLogger(__name__)
 | 
						|
 | 
						|
 | 
						|
def get_task_version(task):
 | 
						|
    """Gets a tasks *string* version, whether it is a task object/function."""
 | 
						|
    task_version = getattr(task, 'version')
 | 
						|
    if isinstance(task_version, (list, tuple)):
 | 
						|
        task_version = '.'.join(str(item) for item in task_version)
 | 
						|
    if task_version is not None and not isinstance(task_version,
 | 
						|
                                                   six.string_types):
 | 
						|
        task_version = str(task_version)
 | 
						|
    return task_version
 | 
						|
 | 
						|
 | 
						|
class ExponentialBackoff(object):
 | 
						|
    def __init__(self, attempts, exponent=2):
 | 
						|
        self.attempts = int(attempts)
 | 
						|
        self.exponent = exponent
 | 
						|
 | 
						|
    def __iter__(self):
 | 
						|
        if self.attempts <= 0:
 | 
						|
            raise StopIteration()
 | 
						|
        for i in xrange(0, self.attempts):
 | 
						|
            yield self.exponent ** i
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        return "ExponentialBackoff: %s" % ([str(v) for v in self])
 | 
						|
 | 
						|
 | 
						|
def as_bool(val):
 | 
						|
    if isinstance(val, bool):
 | 
						|
        return val
 | 
						|
    if isinstance(val, six.string_types):
 | 
						|
        if val.lower() in ('f', 'false', '0', 'n', 'no'):
 | 
						|
            return False
 | 
						|
        if val.lower() in ('t', 'true', '1', 'y', 'yes'):
 | 
						|
            return True
 | 
						|
    return bool(val)
 | 
						|
 | 
						|
 | 
						|
def as_int(obj, quiet=False):
 | 
						|
    # Try "2" -> 2
 | 
						|
    try:
 | 
						|
        return int(obj)
 | 
						|
    except (ValueError, TypeError):
 | 
						|
        pass
 | 
						|
    # Try "2.5" -> 2
 | 
						|
    try:
 | 
						|
        return int(float(obj))
 | 
						|
    except (ValueError, TypeError):
 | 
						|
        pass
 | 
						|
    # Eck, not sure what this is then.
 | 
						|
    if not quiet:
 | 
						|
        raise TypeError("Can not translate %s to an integer." % (obj))
 | 
						|
    return obj
 | 
						|
 | 
						|
 | 
						|
def is_version_compatible(version_1, version_2):
 | 
						|
    """Checks for major version compatibility of two *string" versions."""
 | 
						|
    try:
 | 
						|
        version_1_tmp = version.StrictVersion(version_1)
 | 
						|
        version_2_tmp = version.StrictVersion(version_2)
 | 
						|
    except ValueError:
 | 
						|
        version_1_tmp = version.LooseVersion(version_1)
 | 
						|
        version_2_tmp = version.LooseVersion(version_2)
 | 
						|
    version_1 = version_1_tmp
 | 
						|
    version_2 = version_2_tmp
 | 
						|
    if version_1 == version_2 or version_1.version[0] == version_2.version[0]:
 | 
						|
        return True
 | 
						|
    return False
 | 
						|
 | 
						|
 | 
						|
class TransitionNotifier(object):
 | 
						|
    """A utility helper class that can be used to subscribe to
 | 
						|
    notifications of events occuring as well as allow a entity to post said
 | 
						|
    notifications to subscribers.
 | 
						|
    """
 | 
						|
 | 
						|
    RESERVED_KEYS = ('details',)
 | 
						|
    ANY = '*'
 | 
						|
 | 
						|
    def __init__(self):
 | 
						|
        self._listeners = collections.defaultdict(list)
 | 
						|
 | 
						|
    def reset(self):
 | 
						|
        self._listeners = collections.defaultdict(list)
 | 
						|
 | 
						|
    def notify(self, state, details):
 | 
						|
        listeners = list(self._listeners.get(self.ANY, []))
 | 
						|
        for i in self._listeners[state]:
 | 
						|
            if i not in listeners:
 | 
						|
                listeners.append(i)
 | 
						|
        if not listeners:
 | 
						|
            return
 | 
						|
        for (callback, args, kwargs) in listeners:
 | 
						|
            if args is None:
 | 
						|
                args = []
 | 
						|
            if kwargs is None:
 | 
						|
                kwargs = {}
 | 
						|
            kwargs['details'] = details
 | 
						|
            try:
 | 
						|
                callback(state, *args, **kwargs)
 | 
						|
            except Exception:
 | 
						|
                LOG.exception(("Failure calling callback %s to notify about"
 | 
						|
                               " state transition %s"), callback, state)
 | 
						|
 | 
						|
    def register(self, state, callback, args=None, kwargs=None):
 | 
						|
        assert isinstance(callback, collections.Callable)
 | 
						|
        for i, (cb, args, kwargs) in enumerate(self._listeners.get(state, [])):
 | 
						|
            if cb is callback:
 | 
						|
                raise ValueError("Callback %s already registered" % (callback))
 | 
						|
        if kwargs:
 | 
						|
            for k in self.RESERVED_KEYS:
 | 
						|
                if k in kwargs:
 | 
						|
                    raise KeyError(("Reserved key '%s' not allowed in "
 | 
						|
                                    "kwargs") % k)
 | 
						|
            kwargs = copy.copy(kwargs)
 | 
						|
        if args:
 | 
						|
            args = copy.copy(args)
 | 
						|
        self._listeners[state].append((callback, args, kwargs))
 | 
						|
 | 
						|
    def deregister(self, state, callback):
 | 
						|
        if state not in self._listeners:
 | 
						|
            return
 | 
						|
        for i, (cb, args, kwargs) in enumerate(self._listeners[state]):
 | 
						|
            if cb is callback:
 | 
						|
                self._listeners[state].pop(i)
 | 
						|
                break
 | 
						|
 | 
						|
 | 
						|
class Failure(object):
 | 
						|
    """Indicates failure"""
 | 
						|
    # NOTE(imelnikov): flow_utils.FlowFailure uses runner, but
 | 
						|
    #   engine code does not, so we need separate class
 | 
						|
 | 
						|
    def __init__(self, exc_info=None):
 | 
						|
        if exc_info is not None:
 | 
						|
            self._exc_info = exc_info
 | 
						|
        else:
 | 
						|
            self._exc_info = sys.exc_info()
 | 
						|
 | 
						|
    @property
 | 
						|
    def exc_info(self):
 | 
						|
        return self._exc_info
 | 
						|
 | 
						|
    @property
 | 
						|
    def exc(self):
 | 
						|
        return self._exc_info[1]
 | 
						|
 | 
						|
    def reraise(self):
 | 
						|
        raise self.exc_info[0], self.exc_info[1], self.exc_info[2]
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        try:
 | 
						|
            exc_name = self.exc_info[0].__name__
 | 
						|
        except AttributeError:
 | 
						|
            exc_name = str(self.exc_info)
 | 
						|
        return 'Failure: %s: %s' % (exc_name, self.exc_info[1])
 |