~ubuntu-branches/ubuntu/raring/quantum/raring-proposed

« back to all changes in this revision

Viewing changes to quantum/openstack/common/periodic_task.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short, Chuck Short, Yolanda Robla, James Page, Maru Newby
  • Date: 2013-01-11 09:14:35 UTC
  • mfrom: (2.1.17)
  • Revision ID: package-import@ubuntu.com-20130111091435-vaup7dwmtmajy5oe
Tags: 2013.1~g2-0ubuntu1
[ Chuck Short ]
* New upstream version. 
* debian/patches/fix-quantum-configuration.patch: Refreshed.

[ Yolanda Robla ]
* debian/quantum-l3-agent.quantum-metadata-agent.upstart: Add
  upstart configuration for Metadata Agent.
* debian/quantum-l3-agent.install: Added quantum-ns-metadata-proxy,
  quantum-metadata-agent and metadata_agent.ini.
* debian/patches/fix-quantum-configuration.patch: Update rootwrap
  configuration in metadata_agent.ini file.
* debian/changelog: Updated package version
* d/p/fix-quantum-configuration.patch: refresh patches

[ James Page ]
* d/*.install: Install entry points from bin directory instead
  of easy-install ones generated during the package build process
  (LP: #1085038).
* d/control: Drop BD on python-dev-all; its not required.
* d/rules: Install multiple upstart configurations for quantum-l3-agent.
* d/control: Tidy package descriptions.
* d/*.postrm: Drop as debhelper will generate update-rc.d calls in
  maintainer scripts if required.
* d/quantum-common.postinst: Tweak permissions setting so that /etc/quantum
  is not owned/writable by the quantum user, ensure that /etc/quantum/rootwrap*
  is owned by root:root.
* d/*agent*.postinst: Dropped as permissions now correctly set in
  quantum-common.
* d/patches/fix-quantum-configuration.patch: Re-add dropped fixes rootwrap and
  sqlite defaults for all plugins.
* d/control: Added new BD on alembic (>= 0.4.1~), version python-mock >= 1.0b1.

[ Maru Newby ]
* debian/control: Remove unnecessary openvswitch-vswitch dependency
  from quantum-plugin-openvswitch (LP: #1076747).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 
2
 
 
3
#
 
4
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
 
5
#    not use this file except in compliance with the License. You may obtain
 
6
#    a copy of the License at
 
7
#
 
8
#         http://www.apache.org/licenses/LICENSE-2.0
 
9
#
 
10
#    Unless required by applicable law or agreed to in writing, software
 
11
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 
12
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 
13
#    License for the specific language governing permissions and limitations
 
14
#    under the License.
 
15
 
 
16
from quantum.openstack.common.gettextutils import _
 
17
from quantum.openstack.common import log as logging
 
18
 
 
19
LOG = logging.getLogger(__name__)
 
20
 
 
21
 
 
22
def periodic_task(*args, **kwargs):
 
23
    """Decorator to indicate that a method is a periodic task.
 
24
 
 
25
    This decorator can be used in two ways:
 
26
 
 
27
        1. Without arguments '@periodic_task', this will be run on every tick
 
28
           of the periodic scheduler.
 
29
 
 
30
        2. With arguments, @periodic_task(ticks_between_runs=N), this will be
 
31
           run on every N ticks of the periodic scheduler.
 
32
    """
 
33
    def decorator(f):
 
34
        f._periodic_task = True
 
35
        f._ticks_between_runs = kwargs.pop('ticks_between_runs', 0)
 
36
        return f
 
37
 
 
38
    # NOTE(sirp): The `if` is necessary to allow the decorator to be used with
 
39
    # and without parens.
 
40
    #
 
41
    # In the 'with-parens' case (with kwargs present), this function needs to
 
42
    # return a decorator function since the interpreter will invoke it like:
 
43
    #
 
44
    #   periodic_task(*args, **kwargs)(f)
 
45
    #
 
46
    # In the 'without-parens' case, the original function will be passed
 
47
    # in as the first argument, like:
 
48
    #
 
49
    #   periodic_task(f)
 
50
    if kwargs:
 
51
        return decorator
 
52
    else:
 
53
        return decorator(args[0])
 
54
 
 
55
 
 
56
class _PeriodicTasksMeta(type):
 
57
    def __init__(cls, names, bases, dict_):
 
58
        """Metaclass that allows us to collect decorated periodic tasks."""
 
59
        super(_PeriodicTasksMeta, cls).__init__(names, bases, dict_)
 
60
 
 
61
        # NOTE(sirp): if the attribute is not present then we must be the base
 
62
        # class, so, go ahead and initialize it. If the attribute is present,
 
63
        # then we're a subclass so make a copy of it so we don't step on our
 
64
        # parent's toes.
 
65
        try:
 
66
            cls._periodic_tasks = cls._periodic_tasks[:]
 
67
        except AttributeError:
 
68
            cls._periodic_tasks = []
 
69
 
 
70
        try:
 
71
            cls._ticks_to_skip = cls._ticks_to_skip.copy()
 
72
        except AttributeError:
 
73
            cls._ticks_to_skip = {}
 
74
 
 
75
        # This uses __dict__ instead of
 
76
        # inspect.getmembers(cls, inspect.ismethod) so only the methods of the
 
77
        # current class are added when this class is scanned, and base classes
 
78
        # are not added redundantly.
 
79
        for value in cls.__dict__.values():
 
80
            if getattr(value, '_periodic_task', False):
 
81
                task = value
 
82
                name = task.__name__
 
83
                cls._periodic_tasks.append((name, task))
 
84
                cls._ticks_to_skip[name] = task._ticks_between_runs
 
85
 
 
86
 
 
87
class PeriodicTasks(object):
 
88
    __metaclass__ = _PeriodicTasksMeta
 
89
 
 
90
    def run_periodic_tasks(self, context, raise_on_error=False):
 
91
        """Tasks to be run at a periodic interval."""
 
92
        for task_name, task in self._periodic_tasks:
 
93
            full_task_name = '.'.join([self.__class__.__name__, task_name])
 
94
 
 
95
            ticks_to_skip = self._ticks_to_skip[task_name]
 
96
            if ticks_to_skip > 0:
 
97
                LOG.debug(_("Skipping %(full_task_name)s, %(ticks_to_skip)s"
 
98
                            " ticks left until next run"), locals())
 
99
                self._ticks_to_skip[task_name] -= 1
 
100
                continue
 
101
 
 
102
            self._ticks_to_skip[task_name] = task._ticks_between_runs
 
103
            LOG.debug(_("Running periodic task %(full_task_name)s"), locals())
 
104
 
 
105
            try:
 
106
                task(self, context)
 
107
            except Exception as e:
 
108
                if raise_on_error:
 
109
                    raise
 
110
                LOG.exception(_("Error during %(full_task_name)s: %(e)s"),
 
111
                              locals())