/usr/lib/python3/dist-packages/maasserver/plugin.py is in python3-django-maas 2.4.0~beta2-6865-gec43e47e6-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 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 | # Copyright 2014-2016 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Twisted Application Plugin code for the MAAS Region."""
__all__ = [
"RegionAllInOneServiceMaker",
"RegionMasterServiceMaker",
"RegionWorkerServiceMaker",
]
import os
import signal
import time
from provisioningserver import logger
from provisioningserver.logger import LegacyLogger
from provisioningserver.utils.debug import (
register_sigusr2_thread_dump_handler,
)
from twisted.application.service import IServiceMaker
from twisted.internet import reactor
from twisted.plugin import IPlugin
from twisted.python.threadable import isInIOThread
from zope.interface import implementer
log = LegacyLogger()
class Options(logger.VerbosityOptions):
"""Command-line options for `regiond`."""
@implementer(IServiceMaker, IPlugin)
class RegionWorkerServiceMaker:
"""Create the worker service for the Twisted plugin."""
options = Options
def __init__(self, name, description):
self.tapname = name
self.description = description
def _set_pdeathsig(self):
# Worker must die when the the master dies, no exceptions, no hanging
# around so it must be killed.
#
# Sadly the only way to do this in python is to use ctypes. This tells
# the kernel that when my parent dies to kill me.
import ctypes
libc = ctypes.CDLL("libc.so.6")
libc.prctl(1, signal.SIGKILL)
def _configureThreads(self):
from maasserver.utils import threads
threads.install_default_pool()
threads.install_database_pool()
def _configureLogging(self, verbosity: int):
# Get something going with the logs.
logger.configure(verbosity, logger.LoggingMode.TWISTD)
def _configureDjango(self):
# Some region services use the ORM at class-load time: force Django to
# load the models first. This is OK to run in the reactor because
# having Django -- most specifically the ORM -- up and running is a
# prerequisite of almost everything in the region controller.
import django
django.setup()
def _configureReactor(self):
# Disable all database connections in the reactor.
from maasserver.utils.orm import disable_all_database_connections
if isInIOThread():
disable_all_database_connections()
else:
reactor.callFromThread(disable_all_database_connections)
def _configureCrochet(self):
# Prevent other libraries from starting the reactor via crochet.
# In other words, this makes crochet.setup() a no-op.
import crochet
crochet.no_setup()
def makeService(self, options):
"""Construct the MAAS Region service."""
register_sigusr2_thread_dump_handler()
self._set_pdeathsig()
self._configureThreads()
self._configureLogging(options["verbosity"])
self._configureDjango()
self._configureReactor()
self._configureCrochet()
# Should the import services run in this worker.
import_services = False
if os.environ.get('MAAS_REGIOND_RUN_IMPORTER_SERVICE') == 'true':
import_services = True
# Populate the region's event-loop with services.
from maasserver import eventloop
eventloop.loop.populate(master=False, import_services=import_services)
# Return the eventloop's services to twistd, which will then be
# responsible for starting them all.
return eventloop.loop.services
@implementer(IServiceMaker, IPlugin)
class RegionMasterServiceMaker(RegionWorkerServiceMaker):
"""Create the master service for the Twisted plugin."""
options = Options
def __init__(self, name, description):
self.tapname = name
self.description = description
def _ensureConnection(self):
# If connection is already made close it.
from django.db import connection
if connection.connection is not None:
connection.close()
# Loop forever until a connection can be made.
while True:
try:
connection.ensure_connection()
except Exception:
log.err(_why=(
"Error starting: "
"Connection to database cannot be established."))
time.sleep(1)
else:
# Connection made, now close it.
connection.close()
break
def makeService(self, options):
"""Construct the MAAS Region service."""
register_sigusr2_thread_dump_handler()
self._configureThreads()
self._configureLogging(options["verbosity"])
self._configureDjango()
self._configureReactor()
self._configureCrochet()
self._ensureConnection()
# Populate the region's event-loop with services.
from maasserver import eventloop
eventloop.loop.populate(master=True)
# Return the eventloop's services to twistd, which will then be
# responsible for starting them all.
return eventloop.loop.services
@implementer(IServiceMaker, IPlugin)
class RegionAllInOneServiceMaker(RegionMasterServiceMaker):
"""Create the all-in-one service for the Twisted plugin.
This service runs all the Twisted services in the same process, instead
of forking the workers.
"""
options = Options
def __init__(self, name, description):
self.tapname = name
self.description = description
def makeService(self, options):
"""Construct the MAAS Region service."""
register_sigusr2_thread_dump_handler()
self._configureThreads()
self._configureLogging(options["verbosity"])
self._configureDjango()
self._configureReactor()
self._configureCrochet()
self._ensureConnection()
# Populate the region's event-loop with services.
from maasserver import eventloop
eventloop.loop.populate(
master=True, all_in_one=True, import_services=True)
# Return the eventloop's services to twistd, which will then be
# responsible for starting them all.
return eventloop.loop.services
|