Merge ~andreserl/maas:2.4_lp1779712 into maas:2.4

Proposed by Andres Rodriguez
Status: Merged
Approved by: Andres Rodriguez
Approved revision: 92e4b580beffcdfa37ae8ce2ca70238369da5231
Merge reported by: MAAS Lander
Merged at revision: not available
Proposed branch: ~andreserl/maas:2.4_lp1779712
Merge into: maas:2.4
Diff against target: 408 lines (+150/-2)
11 files modified
src/maasserver/api/tests/test_maas.py (+34/-0)
src/maasserver/compose_preseed.py (+3/-1)
src/maasserver/forms/__init__.py (+1/-0)
src/maasserver/forms/settings.py (+38/-0)
src/maasserver/models/config.py (+1/-0)
src/maasserver/proxyconfig.py (+2/-0)
src/maasserver/tests/test_compose_preseed.py (+23/-0)
src/maasserver/tests/test_proxyconfig.py (+14/-0)
src/maasserver/triggers/system.py (+2/-0)
src/maasserver/triggers/tests/test_system_listener.py (+31/-0)
src/provisioningserver/templates/proxy/maas-proxy.conf.template (+1/-1)
Reviewer Review Type Date Requested Status
Andres Rodriguez (community) Approve
Review via email: mp+349496@code.launchpad.net

Commit message

Backport 2581bde - LP: #1779712 - Ability to select maas-proxy port.

Adds the ability to select which port the MAAS proxy binds to, which is
used by machines during the various operations.

To post a comment you must log in.
Revision history for this message
Andres Rodriguez (andreserl) wrote :

selfie!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/src/maasserver/api/tests/test_maas.py b/src/maasserver/api/tests/test_maas.py
2index 5c4675b..6a54f08 100644
3--- a/src/maasserver/api/tests/test_maas.py
4+++ b/src/maasserver/api/tests/test_maas.py
5@@ -8,6 +8,7 @@ __all__ = []
6 import http.client
7 import json
8 from operator import itemgetter
9+import random
10
11 from django.conf import settings
12 from maasserver.forms.settings import CONFIG_ITEMS_KEYS
13@@ -316,3 +317,36 @@ class MAASHandlerAPITest(APITestCase.ForUser):
14 })
15 self.assertEqual(http.client.OK, response.status_code)
16 self.assertTrue(Config.objects.get_config("boot_images_no_proxy"))
17+
18+
19+class MAASHandlerAPITestForProxyPort(APITestCase.ForUser):
20+
21+ scenarios = [
22+ ('valid-port', {
23+ 'port': random.randint(5300, 65535), 'valid': True}),
24+ ('invalid-port_maas-reserved-range', {
25+ 'port': random.randint(5240, 5270), 'valid': False}),
26+ ('invalid-port_system-services', {
27+ 'port': random.randint(0, 1023), 'valid': False}),
28+ ('invalid-port_out-of-range', {
29+ 'port': random.randint(65536, 70000), 'valid': False}),
30+ ]
31+
32+ def test_set_config_maas_proxy_port(self):
33+ self.become_admin()
34+ port = self.port
35+ response = self.client.post(
36+ reverse('maas_handler'), {
37+ "op": "set_config",
38+ "name": "maas_proxy_port",
39+ "value": port,
40+ })
41+ if self.valid:
42+ self.assertEqual(http.client.OK, response.status_code)
43+ self.assertEqual(
44+ port, Config.objects.get_config("maas_proxy_port"))
45+ else:
46+ self.assertEqual(
47+ http.client.BAD_REQUEST,
48+ response.status_code,
49+ response.content)
50diff --git a/src/maasserver/compose_preseed.py b/src/maasserver/compose_preseed.py
51index cf8897c..8e5897d 100644
52--- a/src/maasserver/compose_preseed.py
53+++ b/src/maasserver/compose_preseed.py
54@@ -41,8 +41,10 @@ def get_apt_proxy(rack_controller=None, default_region_ip=None):
55 if http_proxy and not use_peer_proxy:
56 return http_proxy
57 else:
58+ maas_proxy_port = Config.objects.get_config("maas_proxy_port")
59+ url = "http://:%d/" % maas_proxy_port
60 return compose_URL(
61- "http://:8000/", get_maas_facing_server_host(
62+ url, get_maas_facing_server_host(
63 rack_controller, default_region_ip=default_region_ip))
64 else:
65 return None
66diff --git a/src/maasserver/forms/__init__.py b/src/maasserver/forms/__init__.py
67index 9c4eacd..5e37481 100644
68--- a/src/maasserver/forms/__init__.py
69+++ b/src/maasserver/forms/__init__.py
70@@ -1478,6 +1478,7 @@ class ProxyForm(ConfigForm):
71 use_peer_proxy = get_config_field('use_peer_proxy')
72 http_proxy = get_config_field('http_proxy')
73 prefer_v4_proxy = get_config_field('prefer_v4_proxy')
74+ maas_proxy_port = get_config_field('maas_proxy_port')
75
76
77 class DNSForm(ConfigForm):
78diff --git a/src/maasserver/forms/settings.py b/src/maasserver/forms/settings.py
79index baa0498..a855991 100644
80--- a/src/maasserver/forms/settings.py
81+++ b/src/maasserver/forms/settings.py
82@@ -74,6 +74,26 @@ def make_default_osystem_field(*args, **kwargs):
83 return field
84
85
86+def validate_port(value):
87+ """Raise `ValidationError` when the value is set to a port number. that is
88+ either reserved for known services, or for MAAS services to ensure this
89+ doesn't break MAAS or other applications."""
90+ msg = "Unable to change port number"
91+ if value > 65535 or value <= 0:
92+ raise ValidationError(
93+ "%s. Port number is not between 0 - 65535." % msg)
94+ if value >= 0 and value <= 1023:
95+ raise ValidationError(
96+ "%s. Port number is reserved for system services." % msg)
97+ # 5240 -> reserved for region HTTP.
98+ # 5241 - 4247 -> reserved for other MAAS services.
99+ # 5248 -> reserved for rack HTTP.
100+ # 5250+ -> reserved for region workers (RPC).
101+ if (value >= 5240 and value <= 5270):
102+ raise ValidationError(
103+ "%s. Port number is reserved for MAAS services." % msg)
104+
105+
106 def get_default_usable_osystem(default_osystem):
107 """Return the osystem from the clusters that matches the default_osystem.
108 """
109@@ -92,6 +112,13 @@ def list_choices_for_releases(releases):
110 ]
111
112
113+def make_maas_proxy_port_field(*args, **kwargs):
114+ """Build and return the maas_proxy_port field."""
115+ return forms.IntegerField(
116+ validators=[validate_port],
117+ **kwargs)
118+
119+
120 def make_default_distro_series_field(*args, **kwargs):
121 """Build and return the default_distro_series field."""
122 default_osystem = Config.objects.get_config('default_osystem')
123@@ -225,6 +252,17 @@ CONFIG_ITEMS = {
124 "downloading boot images.")
125 }
126 },
127+ 'maas_proxy_port': {
128+ 'default': 8000,
129+ 'form': make_maas_proxy_port_field,
130+ 'form_kwargs': {
131+ 'label': "Port to bind the MAAS built-in proxy (default: 8000)",
132+ 'required': False,
133+ 'help_text': (
134+ "Defines the port used to bind the built-in proxy. The "
135+ "default port is 8000.")
136+ }
137+ },
138 'use_peer_proxy': {
139 'default': False,
140 'form': forms.BooleanField,
141diff --git a/src/maasserver/models/config.py b/src/maasserver/models/config.py
142index 6c58737..199e9ee 100644
143--- a/src/maasserver/models/config.py
144+++ b/src/maasserver/models/config.py
145@@ -71,6 +71,7 @@ def get_default_config():
146 'default_distro_series': DEFAULT_OS.get_default_release(),
147 # Proxy settings
148 'enable_http_proxy': True,
149+ 'maas_proxy_port': 8000,
150 'use_peer_proxy': False,
151 'http_proxy': None,
152 'prefer_v4_proxy': False,
153diff --git a/src/maasserver/proxyconfig.py b/src/maasserver/proxyconfig.py
154index a7599df..ae36244 100644
155--- a/src/maasserver/proxyconfig.py
156+++ b/src/maasserver/proxyconfig.py
157@@ -71,6 +71,7 @@ def proxy_update_config(reload_proxy=True):
158 cidrs = [subnet.cidr for subnet in allowed_subnets]
159
160 http_proxy = Config.objects.get_config("http_proxy")
161+ maas_proxy_port = Config.objects.get_config("maas_proxy_port")
162 upstream_proxy_enabled = (
163 Config.objects.get_config("use_peer_proxy") and http_proxy)
164 dns_v4_first = Config.objects.get_config("prefer_v4_proxy")
165@@ -85,6 +86,7 @@ def proxy_update_config(reload_proxy=True):
166 'snap_common_path': snappy.get_snap_common_path(),
167 'upstream_peer_proxy': upstream_proxy_enabled,
168 'dns_v4_first': dns_v4_first,
169+ 'maas_proxy_port': maas_proxy_port,
170 }
171
172 proxy_enabled = Config.objects.get_config("enable_http_proxy")
173diff --git a/src/maasserver/tests/test_compose_preseed.py b/src/maasserver/tests/test_compose_preseed.py
174index 90f0529..eb9bccf 100644
175--- a/src/maasserver/tests/test_compose_preseed.py
176+++ b/src/maasserver/tests/test_compose_preseed.py
177@@ -50,6 +50,7 @@ class TestAptProxy(MAASServerTestCase):
178 ("ipv6", dict(
179 default_region_ip=None,
180 rack='2001:db8::1',
181+ maas_proxy_port='',
182 result='http://[2001:db8::1]:8000/',
183 enable=True,
184 use_peer_proxy=False,
185@@ -57,6 +58,7 @@ class TestAptProxy(MAASServerTestCase):
186 ("ipv4", dict(
187 default_region_ip=None,
188 rack='10.0.1.1',
189+ maas_proxy_port=8000,
190 result='http://10.0.1.1:8000/',
191 enable=True,
192 use_peer_proxy=False,
193@@ -64,6 +66,7 @@ class TestAptProxy(MAASServerTestCase):
194 ("builtin", dict(
195 default_region_ip=None,
196 rack='region.example.com',
197+ maas_proxy_port=8000,
198 result='http://region.example.com:8000/',
199 enable=True,
200 use_peer_proxy=False,
201@@ -71,6 +74,7 @@ class TestAptProxy(MAASServerTestCase):
202 ("external", dict(
203 default_region_ip=None,
204 rack='region.example.com',
205+ maas_proxy_port='',
206 result='http://proxy.example.com:111/',
207 enable=True,
208 use_peer_proxy=False,
209@@ -78,6 +82,7 @@ class TestAptProxy(MAASServerTestCase):
210 ("peer-proxy", dict(
211 default_region_ip=None,
212 rack='region.example.com',
213+ maas_proxy_port='',
214 result='http://region.example.com:8000/',
215 enable=True,
216 use_peer_proxy=True,
217@@ -85,6 +90,7 @@ class TestAptProxy(MAASServerTestCase):
218 ("disabled", dict(
219 default_region_ip=None,
220 rack='example.com',
221+ maas_proxy_port=8000,
222 result=None,
223 enable=False,
224 use_peer_proxy=False,
225@@ -95,6 +101,7 @@ class TestAptProxy(MAASServerTestCase):
226 ("ipv6_default", dict(
227 default_region_ip='2001:db8::2',
228 rack='',
229+ maas_proxy_port=8000,
230 result='http://[2001:db8::2]:8000/',
231 enable=True,
232 use_peer_proxy=False,
233@@ -102,6 +109,7 @@ class TestAptProxy(MAASServerTestCase):
234 ("ipv4_default", dict(
235 default_region_ip='10.0.1.2',
236 rack='',
237+ maas_proxy_port=8000,
238 result='http://10.0.1.2:8000/',
239 enable=True,
240 use_peer_proxy=False,
241@@ -109,6 +117,7 @@ class TestAptProxy(MAASServerTestCase):
242 ("builtin_default", dict(
243 default_region_ip='region.example.com',
244 rack='',
245+ maas_proxy_port=8000,
246 result='http://region.example.com:8000/',
247 enable=True,
248 use_peer_proxy=False,
249@@ -116,6 +125,7 @@ class TestAptProxy(MAASServerTestCase):
250 ("external_default", dict(
251 default_region_ip='10.0.0.1',
252 rack='',
253+ maas_proxy_port=8000,
254 result='http://proxy.example.com:111/',
255 enable=True,
256 use_peer_proxy=False,
257@@ -123,6 +133,7 @@ class TestAptProxy(MAASServerTestCase):
258 ("peer-proxy_default", dict(
259 default_region_ip='region2.example.com',
260 rack='',
261+ maas_proxy_port=8000,
262 result='http://region2.example.com:8000/',
263 enable=True,
264 use_peer_proxy=True,
265@@ -130,10 +141,19 @@ class TestAptProxy(MAASServerTestCase):
266 ("disabled_default", dict(
267 default_region_ip='10.0.0.1',
268 rack='',
269+ maas_proxy_port=8000,
270 result=None,
271 enable=False,
272 use_peer_proxy=False,
273 http_proxy='')),
274+ ("changed-maas_proxy_port", dict(
275+ default_region_ip='region2.example.com',
276+ rack='',
277+ maas_proxy_port=9000,
278+ result='http://region2.example.com:9000/',
279+ enable=True,
280+ use_peer_proxy=True,
281+ http_proxy='http://proxy.example.com:111/')),
282 )
283
284 def test__returns_correct_url(self):
285@@ -153,6 +173,9 @@ class TestAptProxy(MAASServerTestCase):
286 Config.objects.set_config("enable_http_proxy", self.enable)
287 Config.objects.set_config("http_proxy", self.http_proxy)
288 Config.objects.set_config("use_peer_proxy", self.use_peer_proxy)
289+ if self.maas_proxy_port:
290+ Config.objects.set_config(
291+ "maas_proxy_port", self.maas_proxy_port)
292 actual = get_apt_proxy(
293 node.get_boot_rack_controller(),
294 default_region_ip=self.default_region_ip)
295diff --git a/src/maasserver/tests/test_proxyconfig.py b/src/maasserver/tests/test_proxyconfig.py
296index 489c1f5..99faa9e 100644
297--- a/src/maasserver/tests/test_proxyconfig.py
298+++ b/src/maasserver/tests/test_proxyconfig.py
299@@ -7,6 +7,7 @@ __all__ = []
300
301 import os
302 from pathlib import Path
303+import random
304
305 from crochet import wait_for
306 from django.conf import settings
307@@ -178,6 +179,19 @@ class TestProxyUpdateConfig(MAASTransactionServerTestCase):
308
309 @wait_for_reactor
310 @inlineCallbacks
311+ def test__with_new_maas_proxy_port_changes_port(self):
312+ self.patch(settings, "PROXY_CONNECT", True)
313+ port = random.randint(1, 65535)
314+ yield deferToDatabase(
315+ transactional(Config.objects.set_config),
316+ "maas_proxy_port", port)
317+ yield proxyconfig.proxy_update_config(reload_proxy=False)
318+ with self.proxy_path.open() as proxy_file:
319+ lines = [line.strip() for line in proxy_file.readlines()]
320+ self.assertIn('http_port %s' % port, lines)
321+
322+ @wait_for_reactor
323+ @inlineCallbacks
324 def test__calls_reloadService(self):
325 self.patch(settings, "PROXY_CONNECT", True)
326 yield deferToDatabase(self.make_subnet)
327diff --git a/src/maasserver/triggers/system.py b/src/maasserver/triggers/system.py
328index fea7b28..4cb656b 100644
329--- a/src/maasserver/triggers/system.py
330+++ b/src/maasserver/triggers/system.py
331@@ -1598,6 +1598,7 @@ PEER_PROXY_CONFIG_INSERT = dedent("""\
332 RETURNS trigger as $$
333 BEGIN
334 IF (NEW.name = 'enable_proxy' OR
335+ NEW.name = 'maas_proxy_port' OR
336 NEW.name = 'use_peer_proxy' OR
337 NEW.name = 'http_proxy' OR
338 NEW.name = 'prefer_v4_proxy') THEN
339@@ -1615,6 +1616,7 @@ PEER_PROXY_CONFIG_UPDATE = dedent("""\
340 RETURNS trigger as $$
341 BEGIN
342 IF (NEW.name = 'enable_proxy' OR
343+ NEW.name = 'maas_proxy_port' OR
344 NEW.name = 'use_peer_proxy' OR
345 NEW.name = 'http_proxy' OR
346 NEW.name = 'prefer_v4_proxy') THEN
347diff --git a/src/maasserver/triggers/tests/test_system_listener.py b/src/maasserver/triggers/tests/test_system_listener.py
348index 53598c9..80c6ec8 100644
349--- a/src/maasserver/triggers/tests/test_system_listener.py
350+++ b/src/maasserver/triggers/tests/test_system_listener.py
351@@ -4330,6 +4330,21 @@ class TestProxyListener(
352
353 @wait_for_reactor
354 @inlineCallbacks
355+ def test_sends_message_for_config_insert_maas_proxy_port(self):
356+ yield deferToDatabase(register_system_triggers)
357+ dv = DeferredValue()
358+ listener = self.make_listener_without_delay()
359+ listener.register(
360+ "sys_proxy", lambda *args: dv.set(args))
361+ yield listener.startService()
362+ try:
363+ yield deferToDatabase(self.create_config, "prefer_v4_proxy", 9000)
364+ yield dv.get(timeout=2)
365+ finally:
366+ yield listener.stopService()
367+
368+ @wait_for_reactor
369+ @inlineCallbacks
370 def test_sends_message_for_config_insert_http_proxy(self):
371 yield deferToDatabase(register_system_triggers)
372 dv = DeferredValue()
373@@ -4394,6 +4409,22 @@ class TestProxyListener(
374
375 @wait_for_reactor
376 @inlineCallbacks
377+ def test_sends_message_for_config_update_maas_proxy_port(self):
378+ yield deferToDatabase(register_system_triggers)
379+ yield deferToDatabase(self.create_config, "maas_proxy_port", 8000)
380+ dv = DeferredValue()
381+ listener = self.make_listener_without_delay()
382+ listener.register(
383+ "sys_proxy", lambda *args: dv.set(args))
384+ yield listener.startService()
385+ try:
386+ yield deferToDatabase(self.set_config, "maas_proxy_port", 9000)
387+ yield dv.get(timeout=2)
388+ finally:
389+ yield listener.stopService()
390+
391+ @wait_for_reactor
392+ @inlineCallbacks
393 def test_sends_message_for_config_update_http_proxy(self):
394 yield deferToDatabase(register_system_triggers)
395 yield deferToDatabase(
396diff --git a/src/provisioningserver/templates/proxy/maas-proxy.conf.template b/src/provisioningserver/templates/proxy/maas-proxy.conf.template
397index e774ccc..2ff2080 100644
398--- a/src/provisioningserver/templates/proxy/maas-proxy.conf.template
399+++ b/src/provisioningserver/templates/proxy/maas-proxy.conf.template
400@@ -23,7 +23,7 @@ http_access allow localnet
401 http_access allow localhost
402 http_access deny all
403 http_port 3128 transparent
404-http_port 8000
405+http_port {{maas_proxy_port}}
406 refresh_pattern ^ftp: 1440 20% 10080
407 refresh_pattern -i (/cgi-bin/|\?) 0 0% 0
408 refresh_pattern \/Release(|\.gpg)$ 0 0% 0 refresh-ims

Subscribers

People subscribed via source and target branches