1
# Copyright 2012 Canonical Ltd. This software is licensed under the
2
# GNU Affero General Public License version 3 (see the file LICENSE).
4
from __future__ import (
9
"""Twisted Application Plugin code for the MaaS provisioning server"""
11
import setproctitle # TODO b-d: python-setproctitle
16
from oops_datedir_repo import DateDirRepo
17
from oops_twisted import (
18
Config as oops_config,
22
from twisted.application.service import (
25
from twisted.internet import reactor
26
from twisted.plugin import IPlugin
27
from twisted.python import (
31
from twisted.python.logfile import LogFile
32
from twisted.python.log import (
36
# TODO b-d: python-twisted
37
from zope.interface import implements
38
# TODO b-d: python-zope.interface
45
def getRotatableLogFileObserver(filename):
46
"""Setup a L{LogFile} for the given application."""
48
logfile = LogFile.fromFullPath(
49
filename, rotateLength=None, defaultMode=0644)
50
def signal_handler(sig, frame):
51
reactor.callFromThread(logfile.reopen)
52
signal.signal(signal.SIGUSR1, signal_handler)
55
return FileLogObserver(logfile)
58
def setUpOOPSHandler(options, logfile):
59
"""Add OOPS handling based on the passed command line options."""
60
config = oops_config()
62
# Add the oops publisher that writes files in the configured place
63
# if the command line option was set.
65
if options["oops-dir"]:
66
repo = DateDirRepo(options["oops-dir"])
67
config.publishers.append(
68
defer_publisher(oops.publish_new_only(repo.publish)))
70
if options["oops-reporter"]:
71
config.template['reporter'] = options["oops-reporter"]
73
observer = OOPSObserver(config, logfile.emit)
74
addObserver(observer.emit)
78
class Options(usage.Options):
79
"""Command line options for the provisioning server."""
82
["logfile", "l", "provisioningserver.log", "Logfile name."],
83
["brokerport", "p", 5672, "Broker port"],
84
["brokerhost", "h", '127.0.0.1', "Broker host"],
85
["brokeruser", "u", None, "Broker user"],
86
["brokerpassword", "a", None, "Broker password"],
87
["brokervhost", "v", '/', "Broker vhost"],
88
["oops-dir", "r", None, "Where to write OOPS reports"],
89
["oops-reporter", "o", "MAAS-PS", "String identifying this service."],
92
def postOptions(self):
93
for arg in ('brokeruser', 'brokerpassword'):
95
raise usage.UsageError("--%s must be specified." % arg)
96
for int_arg in ('brokerport'):
98
self[int_arg] = int(self[int_arg])
99
except (TypeError, ValueError):
100
raise usage.UsageError("--%s must be an integer." % int_arg)
101
if not self["oops-reporter"] and self["oops-dir"]:
102
raise usage.UsageError(
103
"A reporter must be supplied to identify reports "
104
"from this service from other OOPS reports.")
106
class ProvisioningServiceMaker(object):
107
"""Create a service for the Twisted plugin."""
109
implements(IServiceMaker, IPlugin)
111
def __init__(self, name, description):
113
self.description = description
115
def makeService(self, options):
116
"""Construct a service."""
117
# Required to hide the command line options that include a password.
118
setproctitle.setproctitle("maas provisioning service")
120
logfile = getRotatableLogFileObserver(options["logfile"])
121
setUpOOPSHandler(options, logfile)
123
broker_port = options["brokerport"]
124
broker_host = options["brokerhost"]
125
broker_user = options["brokeruser"]
126
broker_password = options["brokerpassword"]
127
broker_vhost = options["brokervhost"]
129
# TODO: Create services here, e.g.
132
# services = MultiService()
133
# services.addService(service1)
134
# services.addService(service2)