/usr/share/pyshared/provisioningserver/plugin.py is in python-maas-provisioningserver 1.2+bzr1373+dfsg-0ubuntu1~12.04.6.
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 | # Copyright 2012 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 provisioning server"""
from __future__ import (
absolute_import,
print_function,
unicode_literals,
)
__metaclass__ = type
__all__ = []
from provisioningserver.amqpclient import AMQFactory
from provisioningserver.config import Config
from provisioningserver.services import (
LogService,
OOPSService,
)
from provisioningserver.tftp import TFTPBackend
from provisioningserver.utils import get_all_interface_addresses
from tftp.protocol import TFTP
from twisted.application import internet
from twisted.application.internet import (
TCPClient,
TCPServer,
)
from twisted.application.service import (
IServiceMaker,
MultiService,
)
from twisted.cred.checkers import ICredentialsChecker
from twisted.cred.credentials import IUsernamePassword
from twisted.cred.error import UnauthorizedLogin
from twisted.cred.portal import IRealm
from twisted.internet.defer import (
inlineCallbacks,
returnValue,
)
from twisted.plugin import IPlugin
from twisted.python import (
log,
usage,
)
from twisted.web.resource import (
IResource,
Resource,
)
from twisted.web.server import Site
from zope.interface import implementer
@implementer(ICredentialsChecker)
class SingleUsernamePasswordChecker:
"""An `ICredentialsChecker` for a single username and password."""
credentialInterfaces = [IUsernamePassword]
def __init__(self, username, password):
super(SingleUsernamePasswordChecker, self).__init__()
self.username = username
self.password = password
@inlineCallbacks
def requestAvatarId(self, credentials):
"""See `ICredentialsChecker`."""
if credentials.username == self.username:
matched = yield credentials.checkPassword(self.password)
if matched:
returnValue(credentials.username)
raise UnauthorizedLogin(credentials.username)
@implementer(IRealm)
class ProvisioningRealm:
"""The `IRealm` for the Provisioning API."""
noop = staticmethod(lambda: None)
def __init__(self, resource):
super(ProvisioningRealm, self).__init__()
self.resource = resource
def requestAvatar(self, avatarId, mind, *interfaces):
"""See `IRealm`."""
if IResource in interfaces:
return (IResource, self.resource, self.noop)
raise NotImplementedError()
class Options(usage.Options):
"""Command line options for the provisioning server."""
optParameters = [
["config-file", "c", "pserv.yaml", "Configuration file to load."],
]
@implementer(IServiceMaker, IPlugin)
class ProvisioningServiceMaker(object):
"""Create a service for the Twisted plugin."""
options = Options
def __init__(self, name, description):
self.tapname = name
self.description = description
def _makeLogService(self, config):
"""Create the log service."""
return LogService(config["logfile"])
def _makeOopsService(self, log_service, oops_config):
"""Create the oops service."""
oops_dir = oops_config["directory"]
oops_reporter = oops_config["reporter"]
return OOPSService(log_service, oops_dir, oops_reporter)
def _makeSiteService(self, papi_xmlrpc, config):
"""Create the site service."""
site_root = Resource()
site_root.putChild("api", papi_xmlrpc)
site = Site(site_root)
site_port = config["port"]
site_interface = config["interface"]
site_service = TCPServer(site_port, site, interface=site_interface)
site_service.setName("site")
return site_service
def _makeBroker(self, broker_config):
"""Create the messaging broker."""
broker_port = broker_config["port"]
broker_host = broker_config["host"]
broker_username = broker_config["username"]
broker_password = broker_config["password"]
broker_vhost = broker_config["vhost"]
cb_connected = lambda ignored: None # TODO
cb_disconnected = lambda ignored: None # TODO
cb_failed = lambda connector_and_reason: (
log.err(connector_and_reason[1], "Connection failed"))
client_factory = AMQFactory(
broker_username, broker_password, broker_vhost,
cb_connected, cb_disconnected, cb_failed)
client_service = TCPClient(
broker_host, broker_port, client_factory)
client_service.setName("amqp")
return client_service
def _makeTFTPService(self, tftp_config):
"""Create the dynamic TFTP service."""
backend = TFTPBackend(tftp_config["root"], tftp_config["generator"])
# Create a UDP server individually for each discovered network
# interface, so that we can detect the interface via which we have
# received a datagram.
tftp_services = MultiService()
tftp_services.setName("tftp")
for address in get_all_interface_addresses():
tftp_service = internet.UDPServer(
tftp_config["port"], TFTP(backend), interface=address)
tftp_service.setName(address)
tftp_service.setServiceParent(tftp_services)
return tftp_services
def makeService(self, options):
"""Construct a service."""
services = MultiService()
config = Config.load(options["config-file"])
log_service = self._makeLogService(config)
log_service.setServiceParent(services)
oops_service = self._makeOopsService(log_service, config["oops"])
oops_service.setServiceParent(services)
broker_config = config["broker"]
# Connecting to RabbitMQ is not yet a required component of a running
# MAAS installation; skip unless the password has been set explicitly.
if broker_config["password"] != b"test":
client_service = self._makeBroker(broker_config)
client_service.setServiceParent(services)
tftp_service = self._makeTFTPService(config["tftp"])
tftp_service.setServiceParent(services)
return services
|