/usr/lib/python2.7/dist-packages/maasserver/eventloop.py is in python-django-maas 1.5+bzr2252-0ubuntu1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | # Copyright 2014 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Event-loop support for the MAAS Region Controller.
This helps start up a background event loop (using Twisted, via crochet)
to handle communications with Cluster Controllers, and any other tasks
that are not tied to an HTTP reqoest.
.. py:data:: loop
The single instance of :py:class:`RegionEventLoop` that's all a
process needs.
.. py:data:: services
The :py:class:`~twisted.application.service.MultiService` which forms
the root of this process's service tree.
This is a convenient reference to :py:attr:`.loop.services`.
.. py:data:: start
Start all the services in :py:data:`services`.
This is a convenient reference to :py:attr:`.loop.start`.
.. py:data:: stop
Stop all the services in :py:data:`services`.
This is a convenient reference to :py:attr:`.loop.stop`.
"""
from __future__ import (
absolute_import,
print_function,
unicode_literals,
)
str = None
__metaclass__ = type
__all__ = [
"loop",
"services",
"start",
"stop",
]
from functools import wraps
from logging import getLogger
from os import getpid
from socket import gethostname
import crochet
from django.utils import autoreload
from twisted.application.service import MultiService
from twisted.internet.error import ReactorNotRunning
logger = getLogger(__name__)
def stop_event_loop_when_reloader_is_invoked():
"""Stop the event loop if Django starts reloading itself.
This typically only happens when using Django's development server.
"""
# The original restart_with_reloader.
restart_with_reloader = autoreload.restart_with_reloader
@wraps(restart_with_reloader)
def stop_event_loop_then_restart_with_reloader():
logger.info("Stopping event loop in process %d", getpid())
try:
crochet.reactor.stop()
except ReactorNotRunning:
pass
return restart_with_reloader()
autoreload.restart_with_reloader = (
stop_event_loop_then_restart_with_reloader)
stop_event_loop_when_reloader_is_invoked()
def make_RegionService():
# Import here to avoid a circular import.
from maasserver.rpc import regionservice
return regionservice.RegionService()
def make_RegionAdvertisingService():
# Import here to avoid a circular import.
from maasserver.rpc import regionservice
return regionservice.RegionAdvertisingService()
class RegionEventLoop:
"""An event loop running in a region controller process.
Typically several processes will be running the web application --
chiefly Django -- across several machines, with multiple threads of
execution in each process.
This class represents a single event loop for each *process*,
allowing convenient control of the event loop -- a Twisted reactor
running in a thread -- and to which to attach and query services.
:cvar factories: A sequence of ``(name, factory)`` tuples. Used to
populate :py:attr:`.services` at start time.
:ivar services:
A :py:class:`~twisted.application.service.MultiService` which
forms the root of the service tree.
"""
factories = (
("rpc", make_RegionService),
("rpc-advertise", make_RegionAdvertisingService),
)
def __init__(self):
super(RegionEventLoop, self).__init__()
self.services = MultiService()
self.handle = None
def init(self):
"""Spin up a Twisted event loop in this process."""
if not crochet.reactor.running:
logger.info("Starting event loop in process %d", getpid())
crochet.setup()
@crochet.run_in_reactor
def start(self):
"""start()
Start all services in the region's event-loop.
"""
for name, factory in self.factories:
try:
self.services.getServiceNamed(name)
except KeyError:
service = factory()
service.setName(name)
service.setServiceParent(self.services)
self.handle = crochet.reactor.addSystemEventTrigger(
'before', 'shutdown', self.services.stopService)
return self.services.startService()
@crochet.run_in_reactor
def stop(self):
"""stop()
Stop all services in the region's event-loop.
"""
if self.handle is not None:
handle, self.handle = self.handle, None
crochet.reactor.removeSystemEventTrigger(handle)
return self.services.stopService()
@property
def name(self):
"""A name for identifying this service in a distributed system."""
return "%s:pid=%d" % (gethostname(), getpid())
loop = RegionEventLoop()
services = loop.services
start = loop.start
stop = loop.stop
loop.init()
|