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

Proposed by Andres Rodriguez
Status: Merged
Approved by: Andres Rodriguez
Approved revision: ec578401c24f610805003ee294e150147f57b417
Merge reported by: MAAS Lander
Merged at revision: not available
Proposed branch: ~andreserl/maas:2.3_lp1779712
Merge into: maas:2.3
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
MAAS Lander unittests Pending
Review via email: mp+349497@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
Revision history for this message
MAAS Lander (maas-lander) wrote :
Revision history for this message
MAAS Lander (maas-lander) wrote :
~andreserl/maas:2.3_lp1779712 updated
ec57840... by Andres Rodriguez

Fix test_sends_message_for_config_insert_maas_proxy_port

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/src/maasserver/api/tests/test_maas.py b/src/maasserver/api/tests/test_maas.py
index fbf89d5..72577a4 100644
--- a/src/maasserver/api/tests/test_maas.py
+++ b/src/maasserver/api/tests/test_maas.py
@@ -8,6 +8,7 @@ __all__ = []
8import http.client8import http.client
9import json9import json
10from operator import itemgetter10from operator import itemgetter
11import random
1112
12from django.conf import settings13from django.conf import settings
13from maasserver.forms.settings import CONFIG_ITEMS_KEYS14from maasserver.forms.settings import CONFIG_ITEMS_KEYS
@@ -303,3 +304,36 @@ class MAASHandlerAPITest(APITestCase.ForUser):
303 })304 })
304 self.assertEqual(http.client.OK, response.status_code)305 self.assertEqual(http.client.OK, response.status_code)
305 self.assertTrue(Config.objects.get_config("boot_images_no_proxy"))306 self.assertTrue(Config.objects.get_config("boot_images_no_proxy"))
307
308
309class MAASHandlerAPITestForProxyPort(APITestCase.ForUser):
310
311 scenarios = [
312 ('valid-port', {
313 'port': random.randint(5300, 65535), 'valid': True}),
314 ('invalid-port_maas-reserved-range', {
315 'port': random.randint(5240, 5270), 'valid': False}),
316 ('invalid-port_system-services', {
317 'port': random.randint(0, 1023), 'valid': False}),
318 ('invalid-port_out-of-range', {
319 'port': random.randint(65536, 70000), 'valid': False}),
320 ]
321
322 def test_set_config_maas_proxy_port(self):
323 self.become_admin()
324 port = self.port
325 response = self.client.post(
326 reverse('maas_handler'), {
327 "op": "set_config",
328 "name": "maas_proxy_port",
329 "value": port,
330 })
331 if self.valid:
332 self.assertEqual(http.client.OK, response.status_code)
333 self.assertEqual(
334 port, Config.objects.get_config("maas_proxy_port"))
335 else:
336 self.assertEqual(
337 http.client.BAD_REQUEST,
338 response.status_code,
339 response.content)
diff --git a/src/maasserver/compose_preseed.py b/src/maasserver/compose_preseed.py
index cf8897c..8e5897d 100644
--- a/src/maasserver/compose_preseed.py
+++ b/src/maasserver/compose_preseed.py
@@ -41,8 +41,10 @@ def get_apt_proxy(rack_controller=None, default_region_ip=None):
41 if http_proxy and not use_peer_proxy:41 if http_proxy and not use_peer_proxy:
42 return http_proxy42 return http_proxy
43 else:43 else:
44 maas_proxy_port = Config.objects.get_config("maas_proxy_port")
45 url = "http://:%d/" % maas_proxy_port
44 return compose_URL(46 return compose_URL(
45 "http://:8000/", get_maas_facing_server_host(47 url, get_maas_facing_server_host(
46 rack_controller, default_region_ip=default_region_ip))48 rack_controller, default_region_ip=default_region_ip))
47 else:49 else:
48 return None50 return None
diff --git a/src/maasserver/forms/__init__.py b/src/maasserver/forms/__init__.py
index cfe7e8c..c24186b 100644
--- a/src/maasserver/forms/__init__.py
+++ b/src/maasserver/forms/__init__.py
@@ -1432,6 +1432,7 @@ class ProxyForm(ConfigForm):
1432 enable_http_proxy = get_config_field('enable_http_proxy')1432 enable_http_proxy = get_config_field('enable_http_proxy')
1433 use_peer_proxy = get_config_field('use_peer_proxy')1433 use_peer_proxy = get_config_field('use_peer_proxy')
1434 http_proxy = get_config_field('http_proxy')1434 http_proxy = get_config_field('http_proxy')
1435 maas_proxy_port = get_config_field('maas_proxy_port')
14351436
14361437
1437class DNSForm(ConfigForm):1438class DNSForm(ConfigForm):
diff --git a/src/maasserver/forms/settings.py b/src/maasserver/forms/settings.py
index ce47aad..339324e 100644
--- a/src/maasserver/forms/settings.py
+++ b/src/maasserver/forms/settings.py
@@ -74,6 +74,26 @@ def make_default_osystem_field(*args, **kwargs):
74 return field74 return field
7575
7676
77def validate_port(value):
78 """Raise `ValidationError` when the value is set to a port number. that is
79 either reserved for known services, or for MAAS services to ensure this
80 doesn't break MAAS or other applications."""
81 msg = "Unable to change port number"
82 if value > 65535 or value <= 0:
83 raise ValidationError(
84 "%s. Port number is not between 0 - 65535." % msg)
85 if value >= 0 and value <= 1023:
86 raise ValidationError(
87 "%s. Port number is reserved for system services." % msg)
88 # 5240 -> reserved for region HTTP.
89 # 5241 - 4247 -> reserved for other MAAS services.
90 # 5248 -> reserved for rack HTTP.
91 # 5250+ -> reserved for region workers (RPC).
92 if (value >= 5240 and value <= 5270):
93 raise ValidationError(
94 "%s. Port number is reserved for MAAS services." % msg)
95
96
77def get_default_usable_osystem(default_osystem):97def get_default_usable_osystem(default_osystem):
78 """Return the osystem from the clusters that matches the default_osystem.98 """Return the osystem from the clusters that matches the default_osystem.
79 """99 """
@@ -92,6 +112,13 @@ def list_choices_for_releases(releases):
92 ]112 ]
93113
94114
115def make_maas_proxy_port_field(*args, **kwargs):
116 """Build and return the maas_proxy_port field."""
117 return forms.IntegerField(
118 validators=[validate_port],
119 **kwargs)
120
121
95def make_default_distro_series_field(*args, **kwargs):122def make_default_distro_series_field(*args, **kwargs):
96 """Build and return the default_distro_series field."""123 """Build and return the default_distro_series field."""
97 default_osystem = Config.objects.get_config('default_osystem')124 default_osystem = Config.objects.get_config('default_osystem')
@@ -225,6 +252,17 @@ CONFIG_ITEMS = {
225 "downloading boot images.")252 "downloading boot images.")
226 }253 }
227 },254 },
255 'maas_proxy_port': {
256 'default': 8000,
257 'form': make_maas_proxy_port_field,
258 'form_kwargs': {
259 'label': "Port to bind the MAAS built-in proxy (default: 8000)",
260 'required': False,
261 'help_text': (
262 "Defines the port used to bind the built-in proxy. The "
263 "default port is 8000.")
264 }
265 },
228 'use_peer_proxy': {266 'use_peer_proxy': {
229 'default': False,267 'default': False,
230 'form': forms.BooleanField,268 'form': forms.BooleanField,
diff --git a/src/maasserver/models/config.py b/src/maasserver/models/config.py
index f5837dc..353e980 100644
--- a/src/maasserver/models/config.py
+++ b/src/maasserver/models/config.py
@@ -69,6 +69,7 @@ def get_default_config():
69 'default_osystem': DEFAULT_OS.name,69 'default_osystem': DEFAULT_OS.name,
70 'default_distro_series': DEFAULT_OS.get_default_release(),70 'default_distro_series': DEFAULT_OS.get_default_release(),
71 'enable_http_proxy': True,71 'enable_http_proxy': True,
72 'maas_proxy_port': 8000,
72 'use_peer_proxy': False,73 'use_peer_proxy': False,
73 'http_proxy': None,74 'http_proxy': None,
74 'upstream_dns': None,75 'upstream_dns': None,
diff --git a/src/maasserver/proxyconfig.py b/src/maasserver/proxyconfig.py
index 1c69be2..64d1d90 100644
--- a/src/maasserver/proxyconfig.py
+++ b/src/maasserver/proxyconfig.py
@@ -71,6 +71,7 @@ def proxy_update_config(reload_proxy=True):
71 cidrs = [subnet.cidr for subnet in allowed_subnets]71 cidrs = [subnet.cidr for subnet in allowed_subnets]
7272
73 http_proxy = Config.objects.get_config("http_proxy")73 http_proxy = Config.objects.get_config("http_proxy")
74 maas_proxy_port = Config.objects.get_config("maas_proxy_port")
74 upstream_proxy_enabled = (75 upstream_proxy_enabled = (
75 Config.objects.get_config("use_peer_proxy") and http_proxy)76 Config.objects.get_config("use_peer_proxy") and http_proxy)
76 context = {77 context = {
@@ -83,6 +84,7 @@ def proxy_update_config(reload_proxy=True):
83 'snap_data_path': snappy.get_snap_data_path(),84 'snap_data_path': snappy.get_snap_data_path(),
84 'snap_common_path': snappy.get_snap_common_path(),85 'snap_common_path': snappy.get_snap_common_path(),
85 'upstream_peer_proxy': upstream_proxy_enabled,86 'upstream_peer_proxy': upstream_proxy_enabled,
87 'maas_proxy_port': maas_proxy_port,
86 }88 }
8789
88 proxy_enabled = Config.objects.get_config("enable_http_proxy")90 proxy_enabled = Config.objects.get_config("enable_http_proxy")
diff --git a/src/maasserver/tests/test_compose_preseed.py b/src/maasserver/tests/test_compose_preseed.py
index 90f0529..eb9bccf 100644
--- a/src/maasserver/tests/test_compose_preseed.py
+++ b/src/maasserver/tests/test_compose_preseed.py
@@ -50,6 +50,7 @@ class TestAptProxy(MAASServerTestCase):
50 ("ipv6", dict(50 ("ipv6", dict(
51 default_region_ip=None,51 default_region_ip=None,
52 rack='2001:db8::1',52 rack='2001:db8::1',
53 maas_proxy_port='',
53 result='http://[2001:db8::1]:8000/',54 result='http://[2001:db8::1]:8000/',
54 enable=True,55 enable=True,
55 use_peer_proxy=False,56 use_peer_proxy=False,
@@ -57,6 +58,7 @@ class TestAptProxy(MAASServerTestCase):
57 ("ipv4", dict(58 ("ipv4", dict(
58 default_region_ip=None,59 default_region_ip=None,
59 rack='10.0.1.1',60 rack='10.0.1.1',
61 maas_proxy_port=8000,
60 result='http://10.0.1.1:8000/',62 result='http://10.0.1.1:8000/',
61 enable=True,63 enable=True,
62 use_peer_proxy=False,64 use_peer_proxy=False,
@@ -64,6 +66,7 @@ class TestAptProxy(MAASServerTestCase):
64 ("builtin", dict(66 ("builtin", dict(
65 default_region_ip=None,67 default_region_ip=None,
66 rack='region.example.com',68 rack='region.example.com',
69 maas_proxy_port=8000,
67 result='http://region.example.com:8000/',70 result='http://region.example.com:8000/',
68 enable=True,71 enable=True,
69 use_peer_proxy=False,72 use_peer_proxy=False,
@@ -71,6 +74,7 @@ class TestAptProxy(MAASServerTestCase):
71 ("external", dict(74 ("external", dict(
72 default_region_ip=None,75 default_region_ip=None,
73 rack='region.example.com',76 rack='region.example.com',
77 maas_proxy_port='',
74 result='http://proxy.example.com:111/',78 result='http://proxy.example.com:111/',
75 enable=True,79 enable=True,
76 use_peer_proxy=False,80 use_peer_proxy=False,
@@ -78,6 +82,7 @@ class TestAptProxy(MAASServerTestCase):
78 ("peer-proxy", dict(82 ("peer-proxy", dict(
79 default_region_ip=None,83 default_region_ip=None,
80 rack='region.example.com',84 rack='region.example.com',
85 maas_proxy_port='',
81 result='http://region.example.com:8000/',86 result='http://region.example.com:8000/',
82 enable=True,87 enable=True,
83 use_peer_proxy=True,88 use_peer_proxy=True,
@@ -85,6 +90,7 @@ class TestAptProxy(MAASServerTestCase):
85 ("disabled", dict(90 ("disabled", dict(
86 default_region_ip=None,91 default_region_ip=None,
87 rack='example.com',92 rack='example.com',
93 maas_proxy_port=8000,
88 result=None,94 result=None,
89 enable=False,95 enable=False,
90 use_peer_proxy=False,96 use_peer_proxy=False,
@@ -95,6 +101,7 @@ class TestAptProxy(MAASServerTestCase):
95 ("ipv6_default", dict(101 ("ipv6_default", dict(
96 default_region_ip='2001:db8::2',102 default_region_ip='2001:db8::2',
97 rack='',103 rack='',
104 maas_proxy_port=8000,
98 result='http://[2001:db8::2]:8000/',105 result='http://[2001:db8::2]:8000/',
99 enable=True,106 enable=True,
100 use_peer_proxy=False,107 use_peer_proxy=False,
@@ -102,6 +109,7 @@ class TestAptProxy(MAASServerTestCase):
102 ("ipv4_default", dict(109 ("ipv4_default", dict(
103 default_region_ip='10.0.1.2',110 default_region_ip='10.0.1.2',
104 rack='',111 rack='',
112 maas_proxy_port=8000,
105 result='http://10.0.1.2:8000/',113 result='http://10.0.1.2:8000/',
106 enable=True,114 enable=True,
107 use_peer_proxy=False,115 use_peer_proxy=False,
@@ -109,6 +117,7 @@ class TestAptProxy(MAASServerTestCase):
109 ("builtin_default", dict(117 ("builtin_default", dict(
110 default_region_ip='region.example.com',118 default_region_ip='region.example.com',
111 rack='',119 rack='',
120 maas_proxy_port=8000,
112 result='http://region.example.com:8000/',121 result='http://region.example.com:8000/',
113 enable=True,122 enable=True,
114 use_peer_proxy=False,123 use_peer_proxy=False,
@@ -116,6 +125,7 @@ class TestAptProxy(MAASServerTestCase):
116 ("external_default", dict(125 ("external_default", dict(
117 default_region_ip='10.0.0.1',126 default_region_ip='10.0.0.1',
118 rack='',127 rack='',
128 maas_proxy_port=8000,
119 result='http://proxy.example.com:111/',129 result='http://proxy.example.com:111/',
120 enable=True,130 enable=True,
121 use_peer_proxy=False,131 use_peer_proxy=False,
@@ -123,6 +133,7 @@ class TestAptProxy(MAASServerTestCase):
123 ("peer-proxy_default", dict(133 ("peer-proxy_default", dict(
124 default_region_ip='region2.example.com',134 default_region_ip='region2.example.com',
125 rack='',135 rack='',
136 maas_proxy_port=8000,
126 result='http://region2.example.com:8000/',137 result='http://region2.example.com:8000/',
127 enable=True,138 enable=True,
128 use_peer_proxy=True,139 use_peer_proxy=True,
@@ -130,10 +141,19 @@ class TestAptProxy(MAASServerTestCase):
130 ("disabled_default", dict(141 ("disabled_default", dict(
131 default_region_ip='10.0.0.1',142 default_region_ip='10.0.0.1',
132 rack='',143 rack='',
144 maas_proxy_port=8000,
133 result=None,145 result=None,
134 enable=False,146 enable=False,
135 use_peer_proxy=False,147 use_peer_proxy=False,
136 http_proxy='')),148 http_proxy='')),
149 ("changed-maas_proxy_port", dict(
150 default_region_ip='region2.example.com',
151 rack='',
152 maas_proxy_port=9000,
153 result='http://region2.example.com:9000/',
154 enable=True,
155 use_peer_proxy=True,
156 http_proxy='http://proxy.example.com:111/')),
137 )157 )
138158
139 def test__returns_correct_url(self):159 def test__returns_correct_url(self):
@@ -153,6 +173,9 @@ class TestAptProxy(MAASServerTestCase):
153 Config.objects.set_config("enable_http_proxy", self.enable)173 Config.objects.set_config("enable_http_proxy", self.enable)
154 Config.objects.set_config("http_proxy", self.http_proxy)174 Config.objects.set_config("http_proxy", self.http_proxy)
155 Config.objects.set_config("use_peer_proxy", self.use_peer_proxy)175 Config.objects.set_config("use_peer_proxy", self.use_peer_proxy)
176 if self.maas_proxy_port:
177 Config.objects.set_config(
178 "maas_proxy_port", self.maas_proxy_port)
156 actual = get_apt_proxy(179 actual = get_apt_proxy(
157 node.get_boot_rack_controller(),180 node.get_boot_rack_controller(),
158 default_region_ip=self.default_region_ip)181 default_region_ip=self.default_region_ip)
diff --git a/src/maasserver/tests/test_proxyconfig.py b/src/maasserver/tests/test_proxyconfig.py
index d64ac19..68aa2b9 100644
--- a/src/maasserver/tests/test_proxyconfig.py
+++ b/src/maasserver/tests/test_proxyconfig.py
@@ -7,6 +7,7 @@ __all__ = []
77
8import os8import os
9from pathlib import Path9from pathlib import Path
10import random
1011
11from crochet import wait_for12from crochet import wait_for
12from django.conf import settings13from django.conf import settings
@@ -154,6 +155,19 @@ class TestProxyUpdateConfig(MAASTransactionServerTestCase):
154155
155 @wait_for_reactor156 @wait_for_reactor
156 @inlineCallbacks157 @inlineCallbacks
158 def test__with_new_maas_proxy_port_changes_port(self):
159 self.patch(settings, "PROXY_CONNECT", True)
160 port = random.randint(1, 65535)
161 yield deferToDatabase(
162 transactional(Config.objects.set_config),
163 "maas_proxy_port", port)
164 yield proxyconfig.proxy_update_config(reload_proxy=False)
165 with self.proxy_path.open() as proxy_file:
166 lines = [line.strip() for line in proxy_file.readlines()]
167 self.assertIn('http_port %s' % port, lines)
168
169 @wait_for_reactor
170 @inlineCallbacks
157 def test__calls_reloadService(self):171 def test__calls_reloadService(self):
158 self.patch(settings, "PROXY_CONNECT", True)172 self.patch(settings, "PROXY_CONNECT", True)
159 yield deferToDatabase(self.make_subnet)173 yield deferToDatabase(self.make_subnet)
diff --git a/src/maasserver/triggers/system.py b/src/maasserver/triggers/system.py
index 7661306..622c8e4 100644
--- a/src/maasserver/triggers/system.py
+++ b/src/maasserver/triggers/system.py
@@ -1590,6 +1590,7 @@ PEER_PROXY_CONFIG_INSERT = dedent("""\
1590 RETURNS trigger as $$1590 RETURNS trigger as $$
1591 BEGIN1591 BEGIN
1592 IF (NEW.name = 'enable_proxy' OR1592 IF (NEW.name = 'enable_proxy' OR
1593 NEW.name = 'maas_proxy_port' OR
1593 NEW.name = 'use_peer_proxy' OR1594 NEW.name = 'use_peer_proxy' OR
1594 NEW.name = 'http_proxy') THEN1595 NEW.name = 'http_proxy') THEN
1595 PERFORM pg_notify('sys_proxy', '');1596 PERFORM pg_notify('sys_proxy', '');
@@ -1606,6 +1607,7 @@ PEER_PROXY_CONFIG_UPDATE = dedent("""\
1606 RETURNS trigger as $$1607 RETURNS trigger as $$
1607 BEGIN1608 BEGIN
1608 IF (NEW.name = 'enable_proxy' OR1609 IF (NEW.name = 'enable_proxy' OR
1610 NEW.name = 'maas_proxy_port' OR
1609 NEW.name = 'use_peer_proxy' OR1611 NEW.name = 'use_peer_proxy' OR
1610 NEW.name = 'http_proxy') THEN1612 NEW.name = 'http_proxy') THEN
1611 PERFORM pg_notify('sys_proxy', '');1613 PERFORM pg_notify('sys_proxy', '');
diff --git a/src/maasserver/triggers/tests/test_system_listener.py b/src/maasserver/triggers/tests/test_system_listener.py
index 9124424..be5cf39 100644
--- a/src/maasserver/triggers/tests/test_system_listener.py
+++ b/src/maasserver/triggers/tests/test_system_listener.py
@@ -4258,6 +4258,21 @@ class TestProxyListener(
42584258
4259 @wait_for_reactor4259 @wait_for_reactor
4260 @inlineCallbacks4260 @inlineCallbacks
4261 def test_sends_message_for_config_insert_maas_proxy_port(self):
4262 yield deferToDatabase(register_system_triggers)
4263 dv = DeferredValue()
4264 listener = self.make_listener_without_delay()
4265 listener.register(
4266 "sys_proxy", lambda *args: dv.set(args))
4267 yield listener.startService()
4268 try:
4269 yield deferToDatabase(self.create_config, "maas_proxy_port", 9000)
4270 yield dv.get(timeout=2)
4271 finally:
4272 yield listener.stopService()
4273
4274 @wait_for_reactor
4275 @inlineCallbacks
4261 def test_sends_message_for_config_insert_http_proxy(self):4276 def test_sends_message_for_config_insert_http_proxy(self):
4262 yield deferToDatabase(register_system_triggers)4277 yield deferToDatabase(register_system_triggers)
4263 dv = DeferredValue()4278 dv = DeferredValue()
@@ -4306,6 +4321,22 @@ class TestProxyListener(
43064321
4307 @wait_for_reactor4322 @wait_for_reactor
4308 @inlineCallbacks4323 @inlineCallbacks
4324 def test_sends_message_for_config_update_maas_proxy_port(self):
4325 yield deferToDatabase(register_system_triggers)
4326 yield deferToDatabase(self.create_config, "maas_proxy_port", 8000)
4327 dv = DeferredValue()
4328 listener = self.make_listener_without_delay()
4329 listener.register(
4330 "sys_proxy", lambda *args: dv.set(args))
4331 yield listener.startService()
4332 try:
4333 yield deferToDatabase(self.set_config, "maas_proxy_port", 9000)
4334 yield dv.get(timeout=2)
4335 finally:
4336 yield listener.stopService()
4337
4338 @wait_for_reactor
4339 @inlineCallbacks
4309 def test_sends_message_for_config_update_http_proxy(self):4340 def test_sends_message_for_config_update_http_proxy(self):
4310 yield deferToDatabase(register_system_triggers)4341 yield deferToDatabase(register_system_triggers)
4311 yield deferToDatabase(4342 yield deferToDatabase(
diff --git a/src/provisioningserver/templates/proxy/maas-proxy.conf.template b/src/provisioningserver/templates/proxy/maas-proxy.conf.template
index 473c83c..ed6f383 100644
--- a/src/provisioningserver/templates/proxy/maas-proxy.conf.template
+++ b/src/provisioningserver/templates/proxy/maas-proxy.conf.template
@@ -23,7 +23,7 @@ http_access allow localnet
23http_access allow localhost23http_access allow localhost
24http_access deny all24http_access deny all
25http_port 3128 transparent25http_port 3128 transparent
26http_port 800026http_port {{maas_proxy_port}}
27refresh_pattern ^ftp: 1440 20% 1008027refresh_pattern ^ftp: 1440 20% 10080
28refresh_pattern -i (/cgi-bin/|\?) 0 0% 028refresh_pattern -i (/cgi-bin/|\?) 0 0% 0
29refresh_pattern \/Release(|\.gpg)$ 0 0% 0 refresh-ims29refresh_pattern \/Release(|\.gpg)$ 0 0% 0 refresh-ims

Subscribers

People subscribed via source and target branches