~mpontillo/maas/dns-template-changes-1.7

« back to all changes in this revision

Viewing changes to src/provisioningserver/plugin.py

  • Committer: Tarmac
  • Author(s): Gavin Panella
  • Date: 2012-02-16 10:10:36 UTC
  • mfrom: (130.2.7 pserv-config-file)
  • Revision ID: ed@carob-20120216101036-y652y5t4vdkmzhg9
[r=jtv][bug=][author=allenap] Use a config file for pserv instead of command-line options.

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
__all__ = []
13
13
 
14
14
from amqpclient import AMQFactory
 
15
from formencode import Schema
 
16
from formencode.validators import (
 
17
    Int,
 
18
    RequireIfPresent,
 
19
    String,
 
20
    )
15
21
from provisioningserver.cobblerclient import CobblerSession
16
22
from provisioningserver.remote import ProvisioningAPI_XMLRPC
17
23
from provisioningserver.services import (
22
28
    FakeCobbler,
23
29
    FakeTwistedProxy,
24
30
    )
25
 
import setproctitle
26
31
from twisted.application.internet import (
27
32
    TCPClient,
28
33
    TCPServer,
38
43
    )
39
44
from twisted.web.resource import Resource
40
45
from twisted.web.server import Site
 
46
import yaml
41
47
from zope.interface import implements
42
48
 
43
49
 
 
50
class ConfigOops(Schema):
 
51
    """Configuration validator for OOPS options."""
 
52
 
 
53
    if_key_missing = None
 
54
 
 
55
    directory = String(if_missing=b"")
 
56
    reporter = String(if_missing=b"")
 
57
 
 
58
    chained_validators = (
 
59
        RequireIfPresent("reporter", present="directory"),
 
60
        )
 
61
 
 
62
 
 
63
class ConfigBroker(Schema):
 
64
    """Configuration validator for message broker options."""
 
65
 
 
66
    if_key_missing = None
 
67
 
 
68
    host = String(if_missing=b"localhost")
 
69
    port = Int(min=1, max=65535, if_missing=5673)
 
70
    username = String(if_missing=None)
 
71
    password = String(if_missing=None)
 
72
    vhost = String(if_missing="/")
 
73
 
 
74
 
 
75
class Config(Schema):
 
76
    """Configuration validator."""
 
77
 
 
78
    if_key_missing = None
 
79
 
 
80
    port = Int(min=1, max=65535, if_missing=8001)
 
81
    logfile = String(not_empty=True)
 
82
    oops = ConfigOops
 
83
    broker = ConfigBroker
 
84
 
 
85
    @classmethod
 
86
    def parse(cls, stream):
 
87
        """Load a YAML configuration from `stream` and validate."""
 
88
        return cls().to_python(yaml.load(stream))
 
89
 
 
90
    @classmethod
 
91
    def load(cls, filename):
 
92
        """Load a YAML configuration from `filename` and validate."""
 
93
        with open(filename, "rb") as stream:
 
94
            return cls.parse(stream)
 
95
 
 
96
 
44
97
class Options(usage.Options):
45
98
    """Command line options for the provisioning server."""
46
99
 
47
100
    optParameters = [
48
 
        ["port", None, 8001, "Port to serve on."],
49
 
        ["logfile", "l", "pserv.log", "Logfile name."],
50
 
        ["oops-dir", "r", None, "Where to write OOPS reports"],
51
 
        ["oops-reporter", "o", "MAAS-PS", "String identifying this service."],
52
 
        ]
53
 
 
54
 
    # Move these back into optParameters when RabbitMQ is a required component
55
 
    # of a running MaaS installation.
56
 
    optParameters_FOR_RABBIT = [
57
 
        ["brokerport", "p", 5672, "Broker port"],
58
 
        ["brokerhost", "h", '127.0.0.1', "Broker host"],
59
 
        ["brokeruser", "u", None, "Broker user"],
60
 
        ["brokerpassword", "a", None, "Broker password"],
61
 
        ["brokervhost", "v", '/', "Broker vhost"],
62
 
        ]
63
 
 
64
 
    def postOptions(self):
65
 
        for int_arg in ('port',):
66
 
            try:
67
 
                self[int_arg] = int(self[int_arg])
68
 
            except (TypeError, ValueError):
69
 
                raise usage.UsageError("--%s must be an integer." % int_arg)
70
 
        if not self["oops-reporter"] and self["oops-dir"]:
71
 
            raise usage.UsageError(
72
 
                "A reporter must be supplied to identify reports "
73
 
                "from this service from other OOPS reports.")
 
101
        ["config-file", "c", "pserv.yaml", "Configuration file to load."],
 
102
        ]
74
103
 
75
104
 
76
105
class ProvisioningServiceMaker(object):
84
113
        self.tapname = name
85
114
        self.description = description
86
115
 
87
 
    def makeService(self, options, _set_proc_title=True):
88
 
        """Construct a service.
89
 
 
90
 
        :param _set_proc_title: For testing; if `False` this will stop the
91
 
            obfuscation of command-line parameters in the process title.
92
 
        """
93
 
        # Required to hide the command line options that include a password.
94
 
        # There is a small window where it can be seen though, between
95
 
        # invocation and when this code runs. TODO: Make this optional (so
96
 
        # that we don't override process title in tests).
97
 
        if _set_proc_title:
98
 
            setproctitle.setproctitle("maas provisioning service")
99
 
 
 
116
    def makeService(self, options):
 
117
        """Construct a service."""
100
118
        services = MultiService()
101
119
 
102
 
        log_service = LogService(options["logfile"])
 
120
        config_file = options["config-file"]
 
121
        if config_file is None:
 
122
            config = Config.parse(b"")
 
123
        else:
 
124
            config = Config.load(config_file)
 
125
 
 
126
        log_service = LogService(config["logfile"])
103
127
        log_service.setServiceParent(services)
104
128
 
105
 
        oops_dir = options["oops-dir"]
106
 
        oops_reporter = options["oops-reporter"]
 
129
        oops_config = config["oops"]
 
130
        oops_dir = oops_config["directory"]
 
131
        oops_reporter = oops_config["reporter"]
107
132
        oops_service = OOPSService(log_service, oops_dir, oops_reporter)
108
133
        oops_service.setServiceParent(services)
109
134
 
110
 
        broker_port = options.get("brokerport")
111
 
        broker_host = options.get("brokerhost")
112
 
        broker_user = options.get("brokeruser")
113
 
        broker_password = options.get("brokerpassword")
114
 
        broker_vhost = options.get("brokervhost")
 
135
        broker_config = config["broker"]
 
136
        broker_port = broker_config["port"]
 
137
        broker_host = broker_config["host"]
 
138
        broker_username = broker_config["username"]
 
139
        broker_password = broker_config["password"]
 
140
        broker_vhost = broker_config["vhost"]
115
141
 
116
142
        # Connecting to RabbitMQ is optional; it is not yet a required
117
143
        # component of a running MaaS installation.
118
 
        if broker_user is not None and broker_password is not None:
 
144
        if broker_username is not None and broker_password is not None:
119
145
            cb_connected = lambda ignored: None  # TODO
120
146
            cb_disconnected = lambda ignored: None  # TODO
121
147
            cb_failed = lambda (connector, reason): (
122
148
                log.err(reason, "Connection failed"))
123
149
            client_factory = AMQFactory(
124
 
                broker_user, broker_password, broker_vhost,
 
150
                broker_username, broker_password, broker_vhost,
125
151
                cb_connected, cb_disconnected, cb_failed)
126
152
            client_service = TCPClient(
127
153
                broker_host, broker_port, client_factory)
140
166
        site_root = Resource()
141
167
        site_root.putChild("api", ProvisioningAPI_XMLRPC(session))
142
168
        site = Site(site_root)
143
 
        site_port = options["port"]
 
169
        site_port = config["port"]
144
170
        site_service = TCPServer(site_port, site)
145
171
        site_service.setName("site")
146
172
        site_service.setServiceParent(services)