Merge lp:~lamont/maas/create-maas-proxy.conf into lp:~maas-committers/maas/trunk
- create-maas-proxy.conf
- Merge into trunk
Proposed by
LaMont Jones
Status: | Merged |
---|---|
Approved by: | LaMont Jones |
Approved revision: | no longer in the source branch. |
Merged at revision: | 4862 |
Proposed branch: | lp:~lamont/maas/create-maas-proxy.conf |
Merge into: | lp:~maas-committers/maas/trunk |
Prerequisite: | lp:~lamont/maas/bug-1379567 |
Diff against target: |
793 lines (+521/-14) 13 files modified
etc/maas/templates/dns/zone.template (+0/-3) src/maas/demo.py (+3/-0) src/maas/development.py (+4/-0) src/maas/settings.py (+5/-0) src/maasserver/migrations/builtin/maasserver/0048_add_subnet_allow_proxy.py (+5/-2) src/maasserver/proxyconfig.py (+86/-0) src/maasserver/region_controller.py (+34/-4) src/maasserver/tests/test_proxyconfig.py (+111/-0) src/maasserver/tests/test_region_controller.py (+96/-5) src/maasserver/triggers/system.py (+50/-0) src/maasserver/triggers/tests/test_system.py (+6/-0) src/maasserver/triggers/tests/test_system_listener.py (+76/-0) src/provisioningserver/templates/proxy/maas-proxy.conf.template (+45/-0) |
To merge this branch: | bzr merge lp:~lamont/maas/create-maas-proxy.conf |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
LaMont Jones (community) | Approve | ||
Blake Rouse (community) | Needs Fixing | ||
Review via email: mp+290154@code.launchpad.net |
Commit message
Create /var/cache/
Description of the change
Create /var/cache/
To post a comment you must log in.
Revision history for this message
LaMont Jones (lamont) wrote : | # |
Marking this approved since merging Blake's changes that were the cause of his "needs fixing".
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'etc/maas/templates/dns/zone.template' | |||
2 | --- etc/maas/templates/dns/zone.template 2016-02-03 09:11:25 +0000 | |||
3 | +++ etc/maas/templates/dns/zone.template 2016-03-31 23:44:54 +0000 | |||
4 | @@ -1,7 +1,4 @@ | |||
5 | 1 | ; Zone file modified: {{modified}}. | 1 | ; Zone file modified: {{modified}}. |
6 | 2 | ; Note that the modification time of this file doesn't reflect | ||
7 | 3 | ; the actual modification time. MAAS controls the modification time | ||
8 | 4 | ; of this file to be able to force the zone to be reloaded by BIND. | ||
9 | 5 | $TTL {{ttl}} | 2 | $TTL {{ttl}} |
10 | 6 | @ IN SOA {{domain}}. nobody.example.com. ( | 3 | @ IN SOA {{domain}}. nobody.example.com. ( |
11 | 7 | {{serial}} ; serial | 4 | {{serial}} ; serial |
12 | 8 | 5 | ||
13 | === modified file 'src/maas/demo.py' | |||
14 | --- src/maas/demo.py 2016-03-25 14:52:23 +0000 | |||
15 | +++ src/maas/demo.py 2016-03-31 23:44:54 +0000 | |||
16 | @@ -27,6 +27,9 @@ | |||
17 | 27 | # Connect to the DHCP server. TODO: Use the signals manager instead. | 27 | # Connect to the DHCP server. TODO: Use the signals manager instead. |
18 | 28 | DHCP_CONNECT = True | 28 | DHCP_CONNECT = True |
19 | 29 | 29 | ||
20 | 30 | # Connect to the PROXY server. TODO: Use the signals manager instead. | ||
21 | 31 | PROXY_CONNECT = True | ||
22 | 32 | |||
23 | 30 | MAAS_CLI = abspath("bin/maas-region") | 33 | MAAS_CLI = abspath("bin/maas-region") |
24 | 31 | 34 | ||
25 | 32 | # For demo purposes, give nodes unauthenticated access to their metadata | 35 | # For demo purposes, give nodes unauthenticated access to their metadata |
26 | 33 | 36 | ||
27 | === modified file 'src/maas/development.py' | |||
28 | --- src/maas/development.py 2016-03-28 20:03:45 +0000 | |||
29 | +++ src/maas/development.py 2016-03-31 23:44:54 +0000 | |||
30 | @@ -33,6 +33,10 @@ | |||
31 | 33 | # basis. TODO: Use the signals manager instead. | 33 | # basis. TODO: Use the signals manager instead. |
32 | 34 | DHCP_CONNECT = False | 34 | DHCP_CONNECT = False |
33 | 35 | 35 | ||
34 | 36 | # Don't setup PROXY servers in tests, this will be enabled on a case per case | ||
35 | 37 | # basis. TODO: Use the signals manager instead. | ||
36 | 38 | PROXY_CONNECT = False | ||
37 | 39 | |||
38 | 36 | # Invalid strings should be visible. | 40 | # Invalid strings should be visible. |
39 | 37 | TEMPLATE_STRING_IF_INVALID = '#### INVALID STRING ####' | 41 | TEMPLATE_STRING_IF_INVALID = '#### INVALID STRING ####' |
40 | 38 | 42 | ||
41 | 39 | 43 | ||
42 | === modified file 'src/maas/settings.py' | |||
43 | --- src/maas/settings.py 2016-03-25 14:52:23 +0000 | |||
44 | +++ src/maas/settings.py 2016-03-31 23:44:54 +0000 | |||
45 | @@ -78,6 +78,11 @@ | |||
46 | 78 | # machinery. TODO: Use the signals manager instead. | 78 | # machinery. TODO: Use the signals manager instead. |
47 | 79 | DHCP_CONNECT = True | 79 | DHCP_CONNECT = True |
48 | 80 | 80 | ||
49 | 81 | # Should the PROXY features be enabled? Having this config option is a | ||
50 | 82 | # debugging/testing feature to be able to quickly disconnect the PROXY | ||
51 | 83 | # machinery. TODO: Use the signals manager instead. | ||
52 | 84 | PROXY_CONNECT = True | ||
53 | 85 | |||
54 | 81 | # The MAAS CLI. | 86 | # The MAAS CLI. |
55 | 82 | MAAS_CLI = 'sudo maas-region' | 87 | MAAS_CLI = 'sudo maas-region' |
56 | 83 | 88 | ||
57 | 84 | 89 | ||
58 | === renamed file 'src/maasserver/migrations/builtin/maasserver/0046_add_subnet_allow_proxy.py' => 'src/maasserver/migrations/builtin/maasserver/0048_add_subnet_allow_proxy.py' | |||
59 | --- src/maasserver/migrations/builtin/maasserver/0046_add_subnet_allow_proxy.py 2016-03-31 23:44:54 +0000 | |||
60 | +++ src/maasserver/migrations/builtin/maasserver/0048_add_subnet_allow_proxy.py 2016-03-31 23:44:54 +0000 | |||
61 | @@ -1,13 +1,16 @@ | |||
62 | 1 | # -*- coding: utf-8 -*- | 1 | # -*- coding: utf-8 -*- |
63 | 2 | from __future__ import unicode_literals | 2 | from __future__ import unicode_literals |
64 | 3 | 3 | ||
66 | 4 | from django.db import migrations, models | 4 | from django.db import ( |
67 | 5 | migrations, | ||
68 | 6 | models, | ||
69 | 7 | ) | ||
70 | 5 | 8 | ||
71 | 6 | 9 | ||
72 | 7 | class Migration(migrations.Migration): | 10 | class Migration(migrations.Migration): |
73 | 8 | 11 | ||
74 | 9 | dependencies = [ | 12 | dependencies = [ |
76 | 10 | ('maasserver', '0045_add_node_to_filesystem'), | 13 | ('maasserver', '0047_fix_spelling_of_degraded'), |
77 | 11 | ] | 14 | ] |
78 | 12 | 15 | ||
79 | 13 | operations = [ | 16 | operations = [ |
80 | 14 | 17 | ||
81 | === added file 'src/maasserver/proxyconfig.py' | |||
82 | --- src/maasserver/proxyconfig.py 1970-01-01 00:00:00 +0000 | |||
83 | +++ src/maasserver/proxyconfig.py 2016-03-31 23:44:54 +0000 | |||
84 | @@ -0,0 +1,86 @@ | |||
85 | 1 | # Copyright 2016 Canonical Ltd. This software is licensed under the | ||
86 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | ||
87 | 3 | |||
88 | 4 | """Proxy config management module.""" | ||
89 | 5 | |||
90 | 6 | __all__ = [ | ||
91 | 7 | 'proxy_update_config', | ||
92 | 8 | ] | ||
93 | 9 | |||
94 | 10 | import datetime | ||
95 | 11 | import os | ||
96 | 12 | import socket | ||
97 | 13 | import sys | ||
98 | 14 | |||
99 | 15 | from django.conf import settings | ||
100 | 16 | from maasserver.models.subnet import Subnet | ||
101 | 17 | from maasserver.service_monitor import service_monitor | ||
102 | 18 | from maasserver.utils.orm import transactional | ||
103 | 19 | from maasserver.utils.threads import deferToDatabase | ||
104 | 20 | from provisioningserver.logger import get_maas_logger | ||
105 | 21 | from provisioningserver.utils import locate_template | ||
106 | 22 | from provisioningserver.utils.fs import atomic_write | ||
107 | 23 | from provisioningserver.utils.twisted import asynchronous | ||
108 | 24 | import tempita | ||
109 | 25 | from twisted.internet.defer import succeed | ||
110 | 26 | |||
111 | 27 | |||
112 | 28 | maaslog = get_maas_logger("dns") | ||
113 | 29 | MAAS_PROXY_CONF_NAME = 'maas-proxy.conf' | ||
114 | 30 | MAAS_PROXY_CONF_TEMPLATE = 'maas-proxy.conf.template' | ||
115 | 31 | |||
116 | 32 | |||
117 | 33 | def is_proxy_enabled(): | ||
118 | 34 | """Is MAAS configured to manage the PROXY?""" | ||
119 | 35 | return settings.PROXY_CONNECT | ||
120 | 36 | |||
121 | 37 | |||
122 | 38 | class ProxyConfigFail(Exception): | ||
123 | 39 | """Raised if there is a problem with the proxy configuration.""" | ||
124 | 40 | |||
125 | 41 | |||
126 | 42 | def get_proxy_config_dir(): | ||
127 | 43 | """Location of bind configuration files.""" | ||
128 | 44 | setting = os.getenv("MAAS_PROXY_CONFIG_DIR", "/var/lib/maas") | ||
129 | 45 | if isinstance(setting, bytes): | ||
130 | 46 | fsenc = sys.getfilesystemencoding() | ||
131 | 47 | return setting.decode(fsenc) | ||
132 | 48 | else: | ||
133 | 49 | return setting | ||
134 | 50 | |||
135 | 51 | |||
136 | 52 | @asynchronous | ||
137 | 53 | def proxy_update_config(reload_proxy=True): | ||
138 | 54 | """Regenerate the proxy configuration file.""" | ||
139 | 55 | |||
140 | 56 | @transactional | ||
141 | 57 | def write_config(): | ||
142 | 58 | allowed_subnets = Subnet.objects.filter(allow_proxy=True) | ||
143 | 59 | cidrs = [subnet.cidr for subnet in allowed_subnets] | ||
144 | 60 | context = { | ||
145 | 61 | 'allowed': allowed_subnets, | ||
146 | 62 | 'modified': str(datetime.date.today()), | ||
147 | 63 | 'fqdn': socket.getfqdn(), | ||
148 | 64 | 'cidrs': cidrs, | ||
149 | 65 | } | ||
150 | 66 | template_path = locate_template('proxy', MAAS_PROXY_CONF_TEMPLATE) | ||
151 | 67 | template = tempita.Template.from_filename( | ||
152 | 68 | template_path, encoding="UTF-8") | ||
153 | 69 | try: | ||
154 | 70 | content = template.substitute(context) | ||
155 | 71 | except NameError as error: | ||
156 | 72 | raise ProxyConfigFail(*error.args) | ||
157 | 73 | # Squid prefers ascii. | ||
158 | 74 | content = content.encode("ascii") | ||
159 | 75 | target_path = os.sep.join( | ||
160 | 76 | [get_proxy_config_dir(), MAAS_PROXY_CONF_NAME]) | ||
161 | 77 | atomic_write(content, target_path, overwrite=True, mode=0o644) | ||
162 | 78 | |||
163 | 79 | if is_proxy_enabled(): | ||
164 | 80 | d = deferToDatabase(write_config) | ||
165 | 81 | if reload_proxy: | ||
166 | 82 | d.addCallback( | ||
167 | 83 | lambda _: service_monitor.reloadService("proxy", if_on=True)) | ||
168 | 84 | return d | ||
169 | 85 | else: | ||
170 | 86 | return succeed(None) | ||
171 | 0 | 87 | ||
172 | === modified file 'src/maasserver/region_controller.py' | |||
173 | --- src/maasserver/region_controller.py 2016-03-28 20:03:45 +0000 | |||
174 | +++ src/maasserver/region_controller.py 2016-03-31 23:44:54 +0000 | |||
175 | @@ -11,6 +11,12 @@ | |||
176 | 11 | 'sys_dns'. Any time a message is recieved on that channel the DNS is marked | 11 | 'sys_dns'. Any time a message is recieved on that channel the DNS is marked |
177 | 12 | as requiring an update. Once marked for update the DNS configuration is | 12 | as requiring an update. Once marked for update the DNS configuration is |
178 | 13 | updated and bind9 is told to reload. | 13 | updated and bind9 is told to reload. |
179 | 14 | |||
180 | 15 | Proxy: | ||
181 | 16 | The regiond process listens for messages from Postgres on channel | ||
182 | 17 | 'sys_proxy'. Any time a message is recieved on that channel the maas-proxy | ||
183 | 18 | is marked as requiring an update. Once marked for update the proxy | ||
184 | 19 | configuration is updated and maas-proxy is told to reload. | ||
185 | 14 | """ | 20 | """ |
186 | 15 | 21 | ||
187 | 16 | __all__ = [ | 22 | __all__ = [ |
188 | @@ -18,6 +24,7 @@ | |||
189 | 18 | ] | 24 | ] |
190 | 19 | 25 | ||
191 | 20 | from maasserver.dns.config import dns_update_all_zones | 26 | from maasserver.dns.config import dns_update_all_zones |
192 | 27 | from maasserver.proxyconfig import proxy_update_config | ||
193 | 21 | from maasserver.utils.orm import transactional | 28 | from maasserver.utils.orm import transactional |
194 | 22 | from maasserver.utils.threads import deferToDatabase | 29 | from maasserver.utils.threads import deferToDatabase |
195 | 23 | from provisioningserver.utils.twisted import ( | 30 | from provisioningserver.utils.twisted import ( |
196 | @@ -26,6 +33,7 @@ | |||
197 | 26 | ) | 33 | ) |
198 | 27 | from twisted.application.service import Service | 34 | from twisted.application.service import Service |
199 | 28 | from twisted.internet import reactor | 35 | from twisted.internet import reactor |
200 | 36 | from twisted.internet.defer import DeferredList | ||
201 | 29 | from twisted.internet.task import LoopingCall | 37 | from twisted.internet.task import LoopingCall |
202 | 30 | from twisted.python import log | 38 | from twisted.python import log |
203 | 31 | 39 | ||
204 | @@ -51,6 +59,7 @@ | |||
205 | 51 | self.processing.clock = self.clock | 59 | self.processing.clock = self.clock |
206 | 52 | self.processingDefer = None | 60 | self.processingDefer = None |
207 | 53 | self.needsDNSUpdate = False | 61 | self.needsDNSUpdate = False |
208 | 62 | self.needsProxyUpdate = False | ||
209 | 54 | self.postgresListener = postgresListener | 63 | self.postgresListener = postgresListener |
210 | 55 | 64 | ||
211 | 56 | @asynchronous(timeout=FOREVER) | 65 | @asynchronous(timeout=FOREVER) |
212 | @@ -58,15 +67,18 @@ | |||
213 | 58 | """Start listening for messages.""" | 67 | """Start listening for messages.""" |
214 | 59 | super(RegionControllerService, self).startService() | 68 | super(RegionControllerService, self).startService() |
215 | 60 | self.postgresListener.register("sys_dns", self.markDNSForUpdate) | 69 | self.postgresListener.register("sys_dns", self.markDNSForUpdate) |
216 | 70 | self.postgresListener.register("sys_proxy", self.markProxyForUpdate) | ||
217 | 61 | 71 | ||
219 | 62 | # Update DNS on first start. | 72 | # Update DNS and proxy on first start. |
220 | 63 | self.markDNSForUpdate(None, None) | 73 | self.markDNSForUpdate(None, None) |
221 | 74 | self.markProxyForUpdate(None, None) | ||
222 | 64 | 75 | ||
223 | 65 | @asynchronous(timeout=FOREVER) | 76 | @asynchronous(timeout=FOREVER) |
224 | 66 | def stopService(self): | 77 | def stopService(self): |
225 | 67 | """Close the controller.""" | 78 | """Close the controller.""" |
226 | 68 | super(RegionControllerService, self).stopService() | 79 | super(RegionControllerService, self).stopService() |
227 | 69 | self.postgresListener.unregister("sys_dns", self.markDNSForUpdate) | 80 | self.postgresListener.unregister("sys_dns", self.markDNSForUpdate) |
228 | 81 | self.postgresListener.unregister("sys_proxy", self.markProxyForUpdate) | ||
229 | 70 | if self.processingDefer is not None: | 82 | if self.processingDefer is not None: |
230 | 71 | self.processingDefer, d = None, self.processingDefer | 83 | self.processingDefer, d = None, self.processingDefer |
231 | 72 | self.processing.stop() | 84 | self.processing.stop() |
232 | @@ -77,13 +89,19 @@ | |||
233 | 77 | self.needsDNSUpdate = True | 89 | self.needsDNSUpdate = True |
234 | 78 | self.startProcessing() | 90 | self.startProcessing() |
235 | 79 | 91 | ||
236 | 92 | def markProxyForUpdate(self, channel, message): | ||
237 | 93 | """Called when the `sys_proxy` message is received.""" | ||
238 | 94 | self.needsProxyUpdate = True | ||
239 | 95 | self.startProcessing() | ||
240 | 96 | |||
241 | 80 | def startProcessing(self): | 97 | def startProcessing(self): |
242 | 81 | """Start the process looping call.""" | 98 | """Start the process looping call.""" |
243 | 82 | if not self.processing.running: | 99 | if not self.processing.running: |
244 | 83 | self.processingDefer = self.processing.start(0.1, now=False) | 100 | self.processingDefer = self.processing.start(0.1, now=False) |
245 | 84 | 101 | ||
246 | 85 | def process(self): | 102 | def process(self): |
248 | 86 | """Process the DNS update.""" | 103 | """Process the DNS and/or proxy update.""" |
249 | 104 | defers = [] | ||
250 | 87 | if self.needsDNSUpdate: | 105 | if self.needsDNSUpdate: |
251 | 88 | self.needsDNSUpdate = False | 106 | self.needsDNSUpdate = False |
252 | 89 | d = deferToDatabase(transactional(dns_update_all_zones)) | 107 | d = deferToDatabase(transactional(dns_update_all_zones)) |
253 | @@ -93,8 +111,20 @@ | |||
254 | 93 | d.addErrback( | 111 | d.addErrback( |
255 | 94 | log.err, | 112 | log.err, |
256 | 95 | "Failed configuring DNS.") | 113 | "Failed configuring DNS.") |
259 | 96 | return d | 114 | defers.append(d) |
260 | 97 | else: | 115 | if self.needsProxyUpdate: |
261 | 116 | self.needsProxyUpdate = False | ||
262 | 117 | d = proxy_update_config(reload_proxy=True) | ||
263 | 118 | d.addCallback( | ||
264 | 119 | lambda _: log.msg( | ||
265 | 120 | "Successfully configured proxy.")) | ||
266 | 121 | d.addErrback( | ||
267 | 122 | log.err, | ||
268 | 123 | "Failed configuring proxy.") | ||
269 | 124 | defers.append(d) | ||
270 | 125 | if len(defers) == 0: | ||
271 | 98 | # Nothing more to do. | 126 | # Nothing more to do. |
272 | 99 | self.processing.stop() | 127 | self.processing.stop() |
273 | 100 | self.processingDefer = None | 128 | self.processingDefer = None |
274 | 129 | else: | ||
275 | 130 | return DeferredList(defers) | ||
276 | 101 | 131 | ||
277 | === added file 'src/maasserver/tests/test_proxyconfig.py' | |||
278 | --- src/maasserver/tests/test_proxyconfig.py 1970-01-01 00:00:00 +0000 | |||
279 | +++ src/maasserver/tests/test_proxyconfig.py 2016-03-31 23:44:54 +0000 | |||
280 | @@ -0,0 +1,111 @@ | |||
281 | 1 | # Copyright 2016 Canonical Ltd. This software is licensed under the | ||
282 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | ||
283 | 3 | |||
284 | 4 | """Tests for the proxyconfig.""" | ||
285 | 5 | |||
286 | 6 | __all__ = [] | ||
287 | 7 | |||
288 | 8 | import os | ||
289 | 9 | |||
290 | 10 | from crochet import wait_for | ||
291 | 11 | from django.conf import settings | ||
292 | 12 | from fixtures import EnvironmentVariableFixture | ||
293 | 13 | from maasserver import proxyconfig | ||
294 | 14 | from maasserver.testing.factory import factory | ||
295 | 15 | from maasserver.testing.testcase import ( | ||
296 | 16 | MAASServerTestCase, | ||
297 | 17 | MAASTransactionServerTestCase, | ||
298 | 18 | ) | ||
299 | 19 | from maasserver.utils.orm import transactional | ||
300 | 20 | from maasserver.utils.threads import deferToDatabase | ||
301 | 21 | from maastesting.matchers import ( | ||
302 | 22 | MockCalledOnceWith, | ||
303 | 23 | MockNotCalled, | ||
304 | 24 | ) | ||
305 | 25 | from testtools.matchers import ( | ||
306 | 26 | Contains, | ||
307 | 27 | FileContains, | ||
308 | 28 | Not, | ||
309 | 29 | ) | ||
310 | 30 | from twisted.internet.defer import inlineCallbacks | ||
311 | 31 | |||
312 | 32 | |||
313 | 33 | wait_for_reactor = wait_for(30) # 30 seconds. | ||
314 | 34 | |||
315 | 35 | |||
316 | 36 | class TestGetConfigDir(MAASServerTestCase): | ||
317 | 37 | """Tests for `maasserver.proxyconfig.get_proxy_config_dir`.""" | ||
318 | 38 | |||
319 | 39 | def test_returns_default(self): | ||
320 | 40 | self.assertEquals( | ||
321 | 41 | "/var/lib/maas", proxyconfig.get_proxy_config_dir()) | ||
322 | 42 | |||
323 | 43 | def test_env_overrides_default(self): | ||
324 | 44 | os.environ['MAAS_PROXY_CONFIG_DIR'] = factory.make_name('env') | ||
325 | 45 | self.assertEquals( | ||
326 | 46 | os.environ['MAAS_PROXY_CONFIG_DIR'], | ||
327 | 47 | proxyconfig.get_proxy_config_dir()) | ||
328 | 48 | del(os.environ['MAAS_PROXY_CONFIG_DIR']) | ||
329 | 49 | |||
330 | 50 | |||
331 | 51 | class TestProxyUpdateConfig(MAASTransactionServerTestCase): | ||
332 | 52 | """Tests for `maasserver.proxyconfig`.""" | ||
333 | 53 | |||
334 | 54 | def setUp(self): | ||
335 | 55 | super(TestProxyUpdateConfig, self).setUp() | ||
336 | 56 | self.tmpdir = self.make_dir() | ||
337 | 57 | self.service_monitor = self.patch(proxyconfig, "service_monitor") | ||
338 | 58 | self.useFixture( | ||
339 | 59 | EnvironmentVariableFixture('MAAS_PROXY_CONFIG_DIR', self.tmpdir)) | ||
340 | 60 | |||
341 | 61 | @transactional | ||
342 | 62 | def make_subnet(self, allow_proxy=True): | ||
343 | 63 | return factory.make_Subnet(allow_proxy=allow_proxy) | ||
344 | 64 | |||
345 | 65 | @wait_for_reactor | ||
346 | 66 | @inlineCallbacks | ||
347 | 67 | def test__only_enabled_subnets_are_present(self): | ||
348 | 68 | self.patch(settings, "PROXY_CONNECT", True) | ||
349 | 69 | disabled = yield deferToDatabase(self.make_subnet, allow_proxy=False) | ||
350 | 70 | enabled = yield deferToDatabase(self.make_subnet) | ||
351 | 71 | yield proxyconfig.proxy_update_config(reload_proxy=False) | ||
352 | 72 | # enabled's cidr must be present | ||
353 | 73 | matcher = Contains("acl localnet src %s" % enabled.cidr) | ||
354 | 74 | self.assertThat( | ||
355 | 75 | "%s/%s" % (self.tmpdir, proxyconfig.MAAS_PROXY_CONF_NAME), | ||
356 | 76 | FileContains(matcher=matcher)) | ||
357 | 77 | # disabled's cidr must not be present | ||
358 | 78 | matcher = Not(Contains("acl localnet src %s" % disabled.cidr)) | ||
359 | 79 | self.assertThat( | ||
360 | 80 | "%s/%s" % (self.tmpdir, proxyconfig.MAAS_PROXY_CONF_NAME), | ||
361 | 81 | FileContains(matcher=matcher)) | ||
362 | 82 | |||
363 | 83 | @wait_for_reactor | ||
364 | 84 | @inlineCallbacks | ||
365 | 85 | def test__calls_reloadService(self): | ||
366 | 86 | self.patch(settings, "PROXY_CONNECT", True) | ||
367 | 87 | yield deferToDatabase(self.make_subnet) | ||
368 | 88 | yield proxyconfig.proxy_update_config() | ||
369 | 89 | self.assertThat( | ||
370 | 90 | self.service_monitor.reloadService, | ||
371 | 91 | MockCalledOnceWith("proxy", if_on=True)) | ||
372 | 92 | |||
373 | 93 | @wait_for_reactor | ||
374 | 94 | @inlineCallbacks | ||
375 | 95 | def test__doesnt_call_reloadService_when_PROXY_CONNECT_False(self): | ||
376 | 96 | self.patch(settings, "PROXY_CONNECT", False) | ||
377 | 97 | yield deferToDatabase(self.make_subnet) | ||
378 | 98 | yield proxyconfig.proxy_update_config() | ||
379 | 99 | self.assertThat( | ||
380 | 100 | self.service_monitor.reloadService, | ||
381 | 101 | MockNotCalled()) | ||
382 | 102 | |||
383 | 103 | @wait_for_reactor | ||
384 | 104 | @inlineCallbacks | ||
385 | 105 | def test__doesnt_call_reloadService_when_reload_proxy_False(self): | ||
386 | 106 | self.patch(settings, "PROXY_CONNECT", True) | ||
387 | 107 | yield deferToDatabase(self.make_subnet) | ||
388 | 108 | yield proxyconfig.proxy_update_config(reload_proxy=False) | ||
389 | 109 | self.assertThat( | ||
390 | 110 | self.service_monitor.reloadService, | ||
391 | 111 | MockNotCalled()) | ||
392 | 0 | 112 | ||
393 | === modified file 'src/maasserver/tests/test_region_controller.py' | |||
394 | --- src/maasserver/tests/test_region_controller.py 2016-03-28 20:03:45 +0000 | |||
395 | +++ src/maasserver/tests/test_region_controller.py 2016-03-31 23:44:54 +0000 | |||
396 | @@ -12,16 +12,22 @@ | |||
397 | 12 | from maasserver.testing.testcase import MAASServerTestCase | 12 | from maasserver.testing.testcase import MAASServerTestCase |
398 | 13 | from maastesting.matchers import ( | 13 | from maastesting.matchers import ( |
399 | 14 | MockCalledOnceWith, | 14 | MockCalledOnceWith, |
400 | 15 | MockCallsMatch, | ||
401 | 15 | MockNotCalled, | 16 | MockNotCalled, |
402 | 16 | ) | 17 | ) |
403 | 17 | from mock import ( | 18 | from mock import ( |
404 | 18 | ANY, | 19 | ANY, |
405 | 20 | call, | ||
406 | 19 | MagicMock, | 21 | MagicMock, |
407 | 20 | sentinel, | 22 | sentinel, |
408 | 21 | ) | 23 | ) |
409 | 22 | from testtools.matchers import MatchesStructure | 24 | from testtools.matchers import MatchesStructure |
410 | 23 | from twisted.internet import reactor | 25 | from twisted.internet import reactor |
412 | 24 | from twisted.internet.defer import inlineCallbacks | 26 | from twisted.internet.defer import ( |
413 | 27 | fail, | ||
414 | 28 | inlineCallbacks, | ||
415 | 29 | succeed, | ||
416 | 30 | ) | ||
417 | 25 | 31 | ||
418 | 26 | 32 | ||
419 | 27 | wait_for_reactor = wait_for(30) # 30 seconds. | 33 | wait_for_reactor = wait_for(30) # 30 seconds. |
420 | @@ -45,22 +51,34 @@ | |||
421 | 45 | service.startService() | 51 | service.startService() |
422 | 46 | self.assertThat( | 52 | self.assertThat( |
423 | 47 | listener.register, | 53 | listener.register, |
425 | 48 | MockCalledOnceWith("sys_dns", service.markDNSForUpdate)) | 54 | MockCallsMatch( |
426 | 55 | call("sys_dns", service.markDNSForUpdate), | ||
427 | 56 | call("sys_proxy", service.markProxyForUpdate))) | ||
428 | 49 | 57 | ||
430 | 50 | def test_startService_sets_needsDNSUpdate_calls_startProcessing(self): | 58 | def test_startService_calls_markDNSForUpdate(self): |
431 | 51 | listener = MagicMock() | 59 | listener = MagicMock() |
432 | 52 | service = RegionControllerService(listener) | 60 | service = RegionControllerService(listener) |
433 | 53 | mock_markDNSForUpdate = self.patch(service, "markDNSForUpdate") | 61 | mock_markDNSForUpdate = self.patch(service, "markDNSForUpdate") |
434 | 54 | service.startService() | 62 | service.startService() |
435 | 55 | self.assertThat(mock_markDNSForUpdate, MockCalledOnceWith(None, None)) | 63 | self.assertThat(mock_markDNSForUpdate, MockCalledOnceWith(None, None)) |
436 | 56 | 64 | ||
437 | 65 | def test_startService_calls_markProxyForUpdate(self): | ||
438 | 66 | listener = MagicMock() | ||
439 | 67 | service = RegionControllerService(listener) | ||
440 | 68 | mock_markProxyForUpdate = self.patch(service, "markProxyForUpdate") | ||
441 | 69 | service.startService() | ||
442 | 70 | self.assertThat( | ||
443 | 71 | mock_markProxyForUpdate, MockCalledOnceWith(None, None)) | ||
444 | 72 | |||
445 | 57 | def test_stopService_calls_unregister_on_the_listener(self): | 73 | def test_stopService_calls_unregister_on_the_listener(self): |
446 | 58 | listener = MagicMock() | 74 | listener = MagicMock() |
447 | 59 | service = RegionControllerService(listener) | 75 | service = RegionControllerService(listener) |
448 | 60 | service.stopService() | 76 | service.stopService() |
449 | 61 | self.assertThat( | 77 | self.assertThat( |
450 | 62 | listener.unregister, | 78 | listener.unregister, |
452 | 63 | MockCalledOnceWith("sys_dns", service.markDNSForUpdate)) | 79 | MockCallsMatch( |
453 | 80 | call("sys_dns", service.markDNSForUpdate), | ||
454 | 81 | call("sys_proxy", service.markProxyForUpdate))) | ||
455 | 64 | 82 | ||
456 | 65 | @wait_for_reactor | 83 | @wait_for_reactor |
457 | 66 | @inlineCallbacks | 84 | @inlineCallbacks |
458 | @@ -71,7 +89,7 @@ | |||
459 | 71 | yield service.stopService() | 89 | yield service.stopService() |
460 | 72 | self.assertIsNone(service.processingDefer) | 90 | self.assertIsNone(service.processingDefer) |
461 | 73 | 91 | ||
463 | 74 | def test_markDNSForUpdate_sets_needsDNSUpdate_and_starts_processing(self): | 92 | def test_markDNSForUpdate_sets_needsDNSUpdate_and_starts_process(self): |
464 | 75 | listener = MagicMock() | 93 | listener = MagicMock() |
465 | 76 | service = RegionControllerService(listener) | 94 | service = RegionControllerService(listener) |
466 | 77 | mock_startProcessing = self.patch(service, "startProcessing") | 95 | mock_startProcessing = self.patch(service, "startProcessing") |
467 | @@ -79,6 +97,14 @@ | |||
468 | 79 | self.assertTrue(service.needsDNSUpdate) | 97 | self.assertTrue(service.needsDNSUpdate) |
469 | 80 | self.assertThat(mock_startProcessing, MockCalledOnceWith()) | 98 | self.assertThat(mock_startProcessing, MockCalledOnceWith()) |
470 | 81 | 99 | ||
471 | 100 | def test_markProxyForUpdate_sets_needsProxyUpdate_and_starts_process(self): | ||
472 | 101 | listener = MagicMock() | ||
473 | 102 | service = RegionControllerService(listener) | ||
474 | 103 | mock_startProcessing = self.patch(service, "startProcessing") | ||
475 | 104 | service.markProxyForUpdate(None, None) | ||
476 | 105 | self.assertTrue(service.needsProxyUpdate) | ||
477 | 106 | self.assertThat(mock_startProcessing, MockCalledOnceWith()) | ||
478 | 107 | |||
479 | 82 | def test_startProcessing_doesnt_call_start_when_looping_call_running(self): | 108 | def test_startProcessing_doesnt_call_start_when_looping_call_running(self): |
480 | 83 | service = RegionControllerService(sentinel.listener) | 109 | service = RegionControllerService(sentinel.listener) |
481 | 84 | mock_start = self.patch(service.processing, "start") | 110 | mock_start = self.patch(service.processing, "start") |
482 | @@ -107,6 +133,17 @@ | |||
483 | 107 | 133 | ||
484 | 108 | @wait_for_reactor | 134 | @wait_for_reactor |
485 | 109 | @inlineCallbacks | 135 | @inlineCallbacks |
486 | 136 | def test_process_doesnt_proxy_update_config_when_nothing_to_process(self): | ||
487 | 137 | service = RegionControllerService(sentinel.listener) | ||
488 | 138 | service.needsProxyUpdate = False | ||
489 | 139 | mock_proxy_update_config = self.patch( | ||
490 | 140 | region_controller, "proxy_update_config") | ||
491 | 141 | service.startProcessing() | ||
492 | 142 | yield service.processingDefer | ||
493 | 143 | self.assertThat(mock_proxy_update_config, MockNotCalled()) | ||
494 | 144 | |||
495 | 145 | @wait_for_reactor | ||
496 | 146 | @inlineCallbacks | ||
497 | 110 | def test_process_stops_processing(self): | 147 | def test_process_stops_processing(self): |
498 | 111 | service = RegionControllerService(sentinel.listener) | 148 | service = RegionControllerService(sentinel.listener) |
499 | 112 | service.needsDNSUpdate = False | 149 | service.needsDNSUpdate = False |
500 | @@ -132,6 +169,24 @@ | |||
501 | 132 | 169 | ||
502 | 133 | @wait_for_reactor | 170 | @wait_for_reactor |
503 | 134 | @inlineCallbacks | 171 | @inlineCallbacks |
504 | 172 | def test_process_updates_proxy(self): | ||
505 | 173 | service = RegionControllerService(sentinel.listener) | ||
506 | 174 | service.needsProxyUpdate = True | ||
507 | 175 | mock_proxy_update_config = self.patch( | ||
508 | 176 | region_controller, "proxy_update_config") | ||
509 | 177 | mock_proxy_update_config.return_value = succeed(None) | ||
510 | 178 | mock_msg = self.patch( | ||
511 | 179 | region_controller.log, "msg") | ||
512 | 180 | service.startProcessing() | ||
513 | 181 | yield service.processingDefer | ||
514 | 182 | self.assertThat( | ||
515 | 183 | mock_proxy_update_config, MockCalledOnceWith(reload_proxy=True)) | ||
516 | 184 | self.assertThat( | ||
517 | 185 | mock_msg, | ||
518 | 186 | MockCalledOnceWith("Successfully configured proxy.")) | ||
519 | 187 | |||
520 | 188 | @wait_for_reactor | ||
521 | 189 | @inlineCallbacks | ||
522 | 135 | def test_process_updates_zones_logs_failure(self): | 190 | def test_process_updates_zones_logs_failure(self): |
523 | 136 | service = RegionControllerService(sentinel.listener) | 191 | service = RegionControllerService(sentinel.listener) |
524 | 137 | service.needsDNSUpdate = True | 192 | service.needsDNSUpdate = True |
525 | @@ -146,3 +201,39 @@ | |||
526 | 146 | self.assertThat( | 201 | self.assertThat( |
527 | 147 | mock_err, | 202 | mock_err, |
528 | 148 | MockCalledOnceWith(ANY, "Failed configuring DNS.")) | 203 | MockCalledOnceWith(ANY, "Failed configuring DNS.")) |
529 | 204 | |||
530 | 205 | @wait_for_reactor | ||
531 | 206 | @inlineCallbacks | ||
532 | 207 | def test_process_updates_proxy_logs_failure(self): | ||
533 | 208 | service = RegionControllerService(sentinel.listener) | ||
534 | 209 | service.needsProxyUpdate = True | ||
535 | 210 | mock_proxy_update_config = self.patch( | ||
536 | 211 | region_controller, "proxy_update_config") | ||
537 | 212 | mock_proxy_update_config.return_value = fail(factory.make_exception()) | ||
538 | 213 | mock_err = self.patch( | ||
539 | 214 | region_controller.log, "err") | ||
540 | 215 | service.startProcessing() | ||
541 | 216 | yield service.processingDefer | ||
542 | 217 | self.assertThat( | ||
543 | 218 | mock_proxy_update_config, MockCalledOnceWith(reload_proxy=True)) | ||
544 | 219 | self.assertThat( | ||
545 | 220 | mock_err, | ||
546 | 221 | MockCalledOnceWith(ANY, "Failed configuring proxy.")) | ||
547 | 222 | |||
548 | 223 | @wait_for_reactor | ||
549 | 224 | @inlineCallbacks | ||
550 | 225 | def test_process_updates_bind_and_proxy(self): | ||
551 | 226 | service = RegionControllerService(sentinel.listener) | ||
552 | 227 | service.needsDNSUpdate = True | ||
553 | 228 | service.needsProxyUpdate = True | ||
554 | 229 | mock_dns_update_all_zones = self.patch( | ||
555 | 230 | region_controller, "dns_update_all_zones") | ||
556 | 231 | mock_proxy_update_config = self.patch( | ||
557 | 232 | region_controller, "proxy_update_config") | ||
558 | 233 | mock_proxy_update_config.return_value = succeed(None) | ||
559 | 234 | service.startProcessing() | ||
560 | 235 | yield service.processingDefer | ||
561 | 236 | self.assertThat( | ||
562 | 237 | mock_dns_update_all_zones, MockCalledOnceWith()) | ||
563 | 238 | self.assertThat( | ||
564 | 239 | mock_proxy_update_config, MockCalledOnceWith(reload_proxy=True)) | ||
565 | 149 | 240 | ||
566 | === modified file 'src/maasserver/triggers/system.py' | |||
567 | --- src/maasserver/triggers/system.py 2016-03-30 13:57:14 +0000 | |||
568 | +++ src/maasserver/triggers/system.py 2016-03-31 23:44:54 +0000 | |||
569 | @@ -880,6 +880,21 @@ | |||
570 | 880 | """) | 880 | """) |
571 | 881 | 881 | ||
572 | 882 | 882 | ||
573 | 883 | # Triggered when a subnet is updated. Increments notifies that proxy needs to | ||
574 | 884 | # be updated. Only watches changes on the cidr and allow_proxy. | ||
575 | 885 | PROXY_SUBNET_UPDATE = dedent("""\ | ||
576 | 886 | CREATE OR REPLACE FUNCTION sys_proxy_subnet_update() | ||
577 | 887 | RETURNS trigger as $$ | ||
578 | 888 | BEGIN | ||
579 | 889 | IF OLD.cidr != NEW.cidr OR OLD.allow_proxy != NEW.allow_proxy THEN | ||
580 | 890 | PERFORM pg_notify('sys_proxy', ''); | ||
581 | 891 | END IF; | ||
582 | 892 | RETURN NEW; | ||
583 | 893 | END; | ||
584 | 894 | $$ LANGUAGE plpgsql; | ||
585 | 895 | """) | ||
586 | 896 | |||
587 | 897 | |||
588 | 883 | def render_sys_dns_procedure(proc_name, on_delete=False): | 898 | def render_sys_dns_procedure(proc_name, on_delete=False): |
589 | 884 | """Render a database procedure with name `proc_name` that increments | 899 | """Render a database procedure with name `proc_name` that increments |
590 | 885 | the zone serial and notifies that a DNS update is needed. | 900 | the zone serial and notifies that a DNS update is needed. |
591 | @@ -899,6 +914,23 @@ | |||
592 | 899 | """ % (proc_name, 'NEW' if not on_delete else 'OLD')) | 914 | """ % (proc_name, 'NEW' if not on_delete else 'OLD')) |
593 | 900 | 915 | ||
594 | 901 | 916 | ||
595 | 917 | def render_sys_proxy_procedure(proc_name, on_delete=False): | ||
596 | 918 | """Render a database procedure with name `proc_name` that notifies that a | ||
597 | 919 | proxy update is needed. | ||
598 | 920 | |||
599 | 921 | :param proc_name: Name of the procedure. | ||
600 | 922 | :param on_delete: True when procedure will be used as a delete trigger. | ||
601 | 923 | """ | ||
602 | 924 | return dedent("""\ | ||
603 | 925 | CREATE OR REPLACE FUNCTION %s() RETURNS trigger AS $$ | ||
604 | 926 | BEGIN | ||
605 | 927 | PERFORM pg_notify('sys_proxy', ''); | ||
606 | 928 | RETURN %s; | ||
607 | 929 | END; | ||
608 | 930 | $$ LANGUAGE plpgsql; | ||
609 | 931 | """ % (proc_name, 'NEW' if not on_delete else 'OLD')) | ||
610 | 932 | |||
611 | 933 | |||
612 | 902 | @transactional | 934 | @transactional |
613 | 903 | def register_system_triggers(): | 935 | def register_system_triggers(): |
614 | 904 | """Register all system triggers into the database.""" | 936 | """Register all system triggers into the database.""" |
615 | @@ -1115,3 +1147,21 @@ | |||
616 | 1115 | "maasserver_config", "sys_dns_config_insert", "insert") | 1147 | "maasserver_config", "sys_dns_config_insert", "insert") |
617 | 1116 | register_trigger( | 1148 | register_trigger( |
618 | 1117 | "maasserver_config", "sys_dns_config_update", "update") | 1149 | "maasserver_config", "sys_dns_config_update", "update") |
619 | 1150 | |||
620 | 1151 | # Proxy | ||
621 | 1152 | |||
622 | 1153 | ## Subnet | ||
623 | 1154 | register_procedure( | ||
624 | 1155 | render_sys_proxy_procedure("sys_proxy_subnet_insert")) | ||
625 | 1156 | register_trigger( | ||
626 | 1157 | "maasserver_subnet", | ||
627 | 1158 | "sys_proxy_subnet_insert", "insert") | ||
628 | 1159 | register_procedure(PROXY_SUBNET_UPDATE) | ||
629 | 1160 | register_trigger( | ||
630 | 1161 | "maasserver_subnet", | ||
631 | 1162 | "sys_proxy_subnet_update", "update") | ||
632 | 1163 | register_procedure( | ||
633 | 1164 | render_sys_proxy_procedure("sys_proxy_subnet_delete", on_delete=True)) | ||
634 | 1165 | register_trigger( | ||
635 | 1166 | "maasserver_subnet", | ||
636 | 1167 | "sys_proxy_subnet_delete", "delete") | ||
637 | 1118 | 1168 | ||
638 | === modified file 'src/maasserver/triggers/tests/test_system.py' | |||
639 | --- src/maasserver/triggers/tests/test_system.py 2016-03-29 20:35:17 +0000 | |||
640 | +++ src/maasserver/triggers/tests/test_system.py 2016-03-31 23:44:54 +0000 | |||
641 | @@ -50,11 +50,17 @@ | |||
642 | 50 | "dnsdata_sys_dns_dnsdata_insert", | 50 | "dnsdata_sys_dns_dnsdata_insert", |
643 | 51 | "dnsdata_sys_dns_dnsdata_update", | 51 | "dnsdata_sys_dns_dnsdata_update", |
644 | 52 | "dnsdata_sys_dns_dnsdata_delete", | 52 | "dnsdata_sys_dns_dnsdata_delete", |
645 | 53 | "subnet_sys_dns_subnet_insert", | ||
646 | 54 | "subnet_sys_dns_subnet_update", | ||
647 | 55 | "subnet_sys_dns_subnet_delete", | ||
648 | 53 | "node_sys_dns_node_update", | 56 | "node_sys_dns_node_update", |
649 | 54 | "node_sys_dns_node_delete", | 57 | "node_sys_dns_node_delete", |
650 | 55 | "interface_sys_dns_interface_update", | 58 | "interface_sys_dns_interface_update", |
651 | 56 | "config_sys_dns_config_insert", | 59 | "config_sys_dns_config_insert", |
652 | 57 | "config_sys_dns_config_update", | 60 | "config_sys_dns_config_update", |
653 | 61 | "subnet_sys_proxy_subnet_insert", | ||
654 | 62 | "subnet_sys_proxy_subnet_update", | ||
655 | 63 | "subnet_sys_proxy_subnet_delete", | ||
656 | 58 | ] | 64 | ] |
657 | 59 | sql, args = psql_array(triggers, sql_type="text") | 65 | sql, args = psql_array(triggers, sql_type="text") |
658 | 60 | with closing(connection.cursor()) as cursor: | 66 | with closing(connection.cursor()) as cursor: |
659 | 61 | 67 | ||
660 | === modified file 'src/maasserver/triggers/tests/test_system_listener.py' | |||
661 | --- src/maasserver/triggers/tests/test_system_listener.py 2016-03-30 13:57:14 +0000 | |||
662 | +++ src/maasserver/triggers/tests/test_system_listener.py 2016-03-31 23:44:54 +0000 | |||
663 | @@ -2966,3 +2966,79 @@ | |||
664 | 2966 | yield self.assertZoneSerialIncrement(zone_serial) | 2966 | yield self.assertZoneSerialIncrement(zone_serial) |
665 | 2967 | finally: | 2967 | finally: |
666 | 2968 | yield listener.stopService() | 2968 | yield listener.stopService() |
667 | 2969 | |||
668 | 2970 | |||
669 | 2971 | class TestProxySubnetListener( | ||
670 | 2972 | MAASTransactionServerTestCase, TransactionalHelpersMixin): | ||
671 | 2973 | """End-to-end test for the proxy triggers code.""" | ||
672 | 2974 | |||
673 | 2975 | @wait_for_reactor | ||
674 | 2976 | @inlineCallbacks | ||
675 | 2977 | def test_sends_message_for_subnet_insert(self): | ||
676 | 2978 | yield deferToDatabase(register_system_triggers) | ||
677 | 2979 | dv = DeferredValue() | ||
678 | 2980 | listener = self.make_listener_without_delay() | ||
679 | 2981 | listener.register( | ||
680 | 2982 | "sys_proxy", lambda *args: dv.set(args)) | ||
681 | 2983 | yield listener.startService() | ||
682 | 2984 | try: | ||
683 | 2985 | yield deferToDatabase(self.create_subnet) | ||
684 | 2986 | yield dv.get(timeout=2) | ||
685 | 2987 | finally: | ||
686 | 2988 | yield listener.stopService() | ||
687 | 2989 | |||
688 | 2990 | @wait_for_reactor | ||
689 | 2991 | @inlineCallbacks | ||
690 | 2992 | def test_sends_message_for_subnet_cidr_update(self): | ||
691 | 2993 | yield deferToDatabase(register_system_triggers) | ||
692 | 2994 | subnet = yield deferToDatabase(self.create_subnet) | ||
693 | 2995 | dv = DeferredValue() | ||
694 | 2996 | listener = self.make_listener_without_delay() | ||
695 | 2997 | listener.register( | ||
696 | 2998 | "sys_proxy", lambda *args: dv.set(args)) | ||
697 | 2999 | yield listener.startService() | ||
698 | 3000 | try: | ||
699 | 3001 | network = factory.make_ip4_or_6_network() | ||
700 | 3002 | yield deferToDatabase(self.update_subnet, subnet.id, { | ||
701 | 3003 | "cidr": str(network.cidr), | ||
702 | 3004 | "gateway_ip": factory.pick_ip_in_network(network), | ||
703 | 3005 | "dns_servers": [], | ||
704 | 3006 | }) | ||
705 | 3007 | yield dv.get(timeout=2) | ||
706 | 3008 | finally: | ||
707 | 3009 | yield listener.stopService() | ||
708 | 3010 | |||
709 | 3011 | @wait_for_reactor | ||
710 | 3012 | @inlineCallbacks | ||
711 | 3013 | def test_sends_message_for_subnet_allow_proxy_update(self): | ||
712 | 3014 | yield deferToDatabase(register_system_triggers) | ||
713 | 3015 | subnet = yield deferToDatabase( | ||
714 | 3016 | self.create_subnet, {"allow_proxy": False}) | ||
715 | 3017 | dv = DeferredValue() | ||
716 | 3018 | listener = self.make_listener_without_delay() | ||
717 | 3019 | listener.register( | ||
718 | 3020 | "sys_proxy", lambda *args: dv.set(args)) | ||
719 | 3021 | yield listener.startService() | ||
720 | 3022 | try: | ||
721 | 3023 | yield deferToDatabase(self.update_subnet, subnet.id, { | ||
722 | 3024 | "allow_proxy": True, | ||
723 | 3025 | }) | ||
724 | 3026 | yield dv.get(timeout=2) | ||
725 | 3027 | finally: | ||
726 | 3028 | yield listener.stopService() | ||
727 | 3029 | |||
728 | 3030 | @wait_for_reactor | ||
729 | 3031 | @inlineCallbacks | ||
730 | 3032 | def test_sends_message_for_subnet_delete(self): | ||
731 | 3033 | yield deferToDatabase(register_system_triggers) | ||
732 | 3034 | subnet = yield deferToDatabase(self.create_subnet) | ||
733 | 3035 | dv = DeferredValue() | ||
734 | 3036 | listener = self.make_listener_without_delay() | ||
735 | 3037 | listener.register( | ||
736 | 3038 | "sys_proxy", lambda *args: dv.set(args)) | ||
737 | 3039 | yield listener.startService() | ||
738 | 3040 | try: | ||
739 | 3041 | yield deferToDatabase(self.delete_subnet, subnet.id) | ||
740 | 3042 | yield dv.get(timeout=2) | ||
741 | 3043 | finally: | ||
742 | 3044 | yield listener.stopService() | ||
743 | 2969 | 3045 | ||
744 | === added directory 'src/provisioningserver/templates/proxy' | |||
745 | === added file 'src/provisioningserver/templates/proxy/maas-proxy.conf.template' | |||
746 | --- src/provisioningserver/templates/proxy/maas-proxy.conf.template 1970-01-01 00:00:00 +0000 | |||
747 | +++ src/provisioningserver/templates/proxy/maas-proxy.conf.template 2016-03-31 23:44:54 +0000 | |||
748 | @@ -0,0 +1,45 @@ | |||
749 | 1 | # DO NOT EDIT. This file is automatically created by MAAS. | ||
750 | 2 | # Last updated at {{modified}}. | ||
751 | 3 | |||
752 | 4 | # Inspired by UDS's conference proxy | ||
753 | 5 | |||
754 | 6 | acl maas_proxy_manager proto cache_object | ||
755 | 7 | acl localhost src 127.0.0.1/32 ::1 | ||
756 | 8 | acl to_localhost dst 127.0.0.0/8 0.0.0.0/32 ::1 | ||
757 | 9 | {{for cidr in cidrs}} | ||
758 | 10 | acl localnet src {{cidr}} | ||
759 | 11 | {{endfor}} | ||
760 | 12 | acl SSL_ports port 443 | ||
761 | 13 | acl Safe_ports port 80 # http | ||
762 | 14 | acl Safe_ports port 21 # ftp | ||
763 | 15 | acl Safe_ports port 443 # https | ||
764 | 16 | acl Safe_ports port 1025-65535 # unregistered ports | ||
765 | 17 | acl CONNECT method CONNECT | ||
766 | 18 | http_access allow maas_proxy_manager localhost | ||
767 | 19 | http_access deny maas_proxy_manager | ||
768 | 20 | http_access deny !Safe_ports | ||
769 | 21 | http_access deny CONNECT !SSL_ports | ||
770 | 22 | http_access allow localnet | ||
771 | 23 | http_access allow localhost | ||
772 | 24 | http_access deny all | ||
773 | 25 | http_port 3128 transparent | ||
774 | 26 | http_port 8000 | ||
775 | 27 | coredump_dir /var/spool/maas-proxy | ||
776 | 28 | refresh_pattern ^ftp: 1440 20% 10080 | ||
777 | 29 | refresh_pattern -i (/cgi-bin/|\?) 0 0% 0 | ||
778 | 30 | refresh_pattern \/Release(|\.gpg)$ 0 0% 0 refresh-ims | ||
779 | 31 | refresh_pattern \/InRelease$ 0 0% 0 refresh-ims | ||
780 | 32 | refresh_pattern \/(Packages|Sources)(|\.bz2|\.gz|\.xz)$ 0 0% 0 refresh-ims | ||
781 | 33 | refresh_pattern \/(Translation-.*)(|\.bz2|\.gz|\.xz)$ 0 0% 0 refresh-ims | ||
782 | 34 | refresh_pattern . 0 20% 4320 | ||
783 | 35 | forwarded_for delete | ||
784 | 36 | visible_hostname {{fqdn}} | ||
785 | 37 | cache_mem 512 MB | ||
786 | 38 | minimum_object_size 0 MB | ||
787 | 39 | maximum_object_size 1024 MB | ||
788 | 40 | maximum_object_size_in_memory 100 MB | ||
789 | 41 | cache_dir aufs /var/spool/maas-proxy 40000 16 256 | ||
790 | 42 | # use different logs | ||
791 | 43 | cache_access_log /var/log/maas/proxy/access.log | ||
792 | 44 | cache_log /var/log/maas/proxy/cache.log | ||
793 | 45 | cache_store_log /var/log/maas/proxy/store.log |
Overall this looks really good. The service reloading needs an improvement to use the serviceMonitor so the service status is kept in sync with what as known about the service.