Merge lp:~jtv/maas/bug-977752 into lp:~maas-committers/maas/trunk

Proposed by Jeroen T. Vermeulen
Status: Merged
Approved by: Jeroen T. Vermeulen
Approved revision: no longer in the source branch.
Merged at revision: 430
Proposed branch: lp:~jtv/maas/bug-977752
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 153 lines (+64/-38)
3 files modified
etc/pserv.yaml (+6/-0)
src/provisioningserver/plugin.py (+57/-38)
src/provisioningserver/tests/test_plugin.py (+1/-0)
To merge this branch: bzr merge lp:~jtv/maas/bug-977752
Reviewer Review Type Date Requested Status
Gavin Panella (community) Approve
Review via email: mp+101346@code.launchpad.net

Commit message

Don't just expose pserv on the network.

Description of the change

With thanks to Julian for showing me what I couldn't find documentation for (“pre-imp”). This makes the provisioning server listen only on the loopback interface. I can't easily do the same for txlongpoll, because its twistd setup is hidden away in upstream code.

After mulling it over with Gavin, I refactored the service setup code a bit so that I could unit-test the resulting smaller methods. But I didn't manage to inject a fake into TCPServer, which apparently is a bit weird and generated on the fly. And so I ended up deleting the test. Better ideas welcome.

Jeroen

To post a comment you must log in.
Revision history for this message
Gavin Panella (allenap) wrote :
Download full text (7.3 KiB)

approve
On Apr 10, 2012 12:18 PM, "Jeroen T. Vermeulen" <email address hidden> wrote:

> Jeroen T. Vermeulen has proposed merging lp:~jtv/maas/bug-977752 into
> lp:maas.
>
> Requested reviews:
> Launchpad code reviewers (launchpad-reviewers)
> Related bugs:
> Bug #975450 in MAAS: "bind all services not required by the nodes to the
> loopback interface or add ingress firewall rules for these services"
> https://bugs.launchpad.net/maas/+bug/975450
>
> For more details, see:
> https://code.launchpad.net/~jtv/maas/bug-977752/+merge/101346
>
> With thanks to Julian for showing me what I couldn't find documentation
> for (“pre-imp”). This makes the provisioning server listen only on the
> loopback interface. I can't easily do the same for txlongpoll, because its
> twistd setup is hidden away in upstream code.
>
> After mulling it over with Gavin, I refactored the service setup code a
> bit so that I could unit-test the resulting smaller methods. But I didn't
> manage to inject a fake into TCPServer, which apparently is a bit weird and
> generated on the fly. And so I ended up deleting the test. Better ideas
> welcome.
>
>
> Jeroen
> --
> https://code.launchpad.net/~jtv/maas/bug-977752/+merge/101346
> You are subscribed to branch lp:maas.
>
> === modified file 'etc/pserv.yaml'
> --- etc/pserv.yaml 2012-04-02 07:06:37 +0000
> +++ etc/pserv.yaml 2012-04-10 10:19:21 +0000
> @@ -6,6 +6,12 @@
> #
> # port: 5241
>
> +## Network interface to bind the service on.
> +# Keep this pointed at the loopback interface unless you really know what
> +# you're doing.
> +#
> +# interface: "127.0.0.1"
> +
> ## Where to log. This log can be rotated by sending SIGUSR1 to the
> ## running server.
> #
>
> === modified file 'src/provisioningserver/plugin.py'
> --- src/provisioningserver/plugin.py 2012-03-15 22:43:55 +0000
> +++ src/provisioningserver/plugin.py 2012-04-10 10:19:21 +0000
> @@ -89,6 +89,7 @@
>
> if_key_missing = None
>
> + interface = String(if_empty=b"", if_missing=b"127.0.0.1")
> port = Int(min=1, max=65535, if_missing=5241)
> logfile = String(if_empty=b"pserv.log", if_missing=b"pserv.log")
> oops = ConfigOops
> @@ -126,56 +127,74 @@
> self.tapname = name
> self.description = description
>
> - def makeService(self, options):
> - """Construct a service."""
> - services = MultiService()
> -
> - config_file = options["config-file"]
> - config = Config.load(config_file)
> -
> - log_service = LogService(config["logfile"])
> - log_service.setServiceParent(services)
> -
> - oops_config = config["oops"]
> + 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"]
> - oops_service = OOPSService(log_service, oops_dir, oops_reporter)
> - oops_service.setServiceParent(services)
> -
> - broker_config = config["broker"]
> + return OOPSService(log_service, oops_dir, ...

Read more...

Revision history for this message
Gavin Panella (allenap) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'etc/pserv.yaml'
2--- etc/pserv.yaml 2012-04-02 07:06:37 +0000
3+++ etc/pserv.yaml 2012-04-10 10:19:21 +0000
4@@ -6,6 +6,12 @@
5 #
6 # port: 5241
7
8+## Network interface to bind the service on.
9+# Keep this pointed at the loopback interface unless you really know what
10+# you're doing.
11+#
12+# interface: "127.0.0.1"
13+
14 ## Where to log. This log can be rotated by sending SIGUSR1 to the
15 ## running server.
16 #
17
18=== modified file 'src/provisioningserver/plugin.py'
19--- src/provisioningserver/plugin.py 2012-03-15 22:43:55 +0000
20+++ src/provisioningserver/plugin.py 2012-04-10 10:19:21 +0000
21@@ -89,6 +89,7 @@
22
23 if_key_missing = None
24
25+ interface = String(if_empty=b"", if_missing=b"127.0.0.1")
26 port = Int(min=1, max=65535, if_missing=5241)
27 logfile = String(if_empty=b"pserv.log", if_missing=b"pserv.log")
28 oops = ConfigOops
29@@ -126,56 +127,74 @@
30 self.tapname = name
31 self.description = description
32
33- def makeService(self, options):
34- """Construct a service."""
35- services = MultiService()
36-
37- config_file = options["config-file"]
38- config = Config.load(config_file)
39-
40- log_service = LogService(config["logfile"])
41- log_service.setServiceParent(services)
42-
43- oops_config = config["oops"]
44+ def _makeLogService(self, config):
45+ """Create the log service."""
46+ return LogService(config["logfile"])
47+
48+ def _makeOopsService(self, log_service, oops_config):
49+ """Create the oops service."""
50 oops_dir = oops_config["directory"]
51 oops_reporter = oops_config["reporter"]
52- oops_service = OOPSService(log_service, oops_dir, oops_reporter)
53- oops_service.setServiceParent(services)
54-
55- broker_config = config["broker"]
56+ return OOPSService(log_service, oops_dir, oops_reporter)
57+
58+ def _makePAPI(self, cobbler_config):
59+ """Create the provisioning XMLRPC API."""
60+ cobbler_session = CobblerSession(
61+ cobbler_config["url"], cobbler_config["username"],
62+ cobbler_config["password"])
63+ return ProvisioningAPI_XMLRPC(cobbler_session)
64+
65+ def _makeSiteService(self, papi_xmlrpc, config):
66+ """Create the site service."""
67+ site_root = Resource()
68+ site_root.putChild("api", papi_xmlrpc)
69+ site = Site(site_root)
70+ site_port = config["port"]
71+ site_interface = config["interface"]
72+ site_service = TCPServer(site_port, site, interface=site_interface)
73+ site_service.setName("site")
74+ return site_service
75+
76+ def _makeBroker(self, broker_config):
77+ """Create the messaging broker."""
78 broker_port = broker_config["port"]
79 broker_host = broker_config["host"]
80 broker_username = broker_config["username"]
81 broker_password = broker_config["password"]
82 broker_vhost = broker_config["vhost"]
83
84+ cb_connected = lambda ignored: None # TODO
85+ cb_disconnected = lambda ignored: None # TODO
86+ cb_failed = lambda connector_and_reason: (
87+ log.err(connector_and_reason[1], "Connection failed"))
88+ client_factory = AMQFactory(
89+ broker_username, broker_password, broker_vhost,
90+ cb_connected, cb_disconnected, cb_failed)
91+ client_service = TCPClient(
92+ broker_host, broker_port, client_factory)
93+ client_service.setName("amqp")
94+ return client_service
95+
96+ def makeService(self, options):
97+ """Construct a service."""
98+ services = MultiService()
99+ config = Config.load(options["config-file"])
100+
101+ log_service = self._makeLogService(config)
102+ log_service.setServiceParent(services)
103+
104+ oops_service = self._makeOopsService(log_service, config["oops"])
105+ oops_service.setServiceParent(services)
106+
107+ broker_config = config["broker"]
108 # Connecting to RabbitMQ is not yet a required component of a running
109 # MAAS installation; skip unless the password has been set explicitly.
110- if broker_password is not b"test":
111- cb_connected = lambda ignored: None # TODO
112- cb_disconnected = lambda ignored: None # TODO
113- cb_failed = lambda connector_and_reason: (
114- log.err(connector_and_reason[1], "Connection failed"))
115- client_factory = AMQFactory(
116- broker_username, broker_password, broker_vhost,
117- cb_connected, cb_disconnected, cb_failed)
118- client_service = TCPClient(
119- broker_host, broker_port, client_factory)
120- client_service.setName("amqp")
121+ if broker_config["password"] is not b"test":
122+ client_service = self._makeBroker(broker_config)
123 client_service.setServiceParent(services)
124
125- cobbler_config = config["cobbler"]
126- cobbler_session = CobblerSession(
127- cobbler_config["url"], cobbler_config["username"],
128- cobbler_config["password"])
129- papi_xmlrpc = ProvisioningAPI_XMLRPC(cobbler_session)
130-
131- site_root = Resource()
132- site_root.putChild("api", papi_xmlrpc)
133- site = Site(site_root)
134- site_port = config["port"]
135- site_service = TCPServer(site_port, site)
136- site_service.setName("site")
137+ papi_xmlrpc = self._makePAPI(config["cobbler"])
138+ site_service = self._makeSiteService(papi_xmlrpc, config)
139 site_service.setServiceParent(services)
140
141 return services
142
143=== modified file 'src/provisioningserver/tests/test_plugin.py'
144--- src/provisioningserver/tests/test_plugin.py 2012-03-21 12:18:48 +0000
145+++ src/provisioningserver/tests/test_plugin.py 2012-04-10 10:19:21 +0000
146@@ -55,6 +55,7 @@
147 'reporter': '',
148 },
149 'port': 5241,
150+ 'interface': '127.0.0.1',
151 }
152 observed = Config.to_python({})
153 self.assertEqual(expected, observed)