Merge ~andreserl/maas:lp1774206_trusted_acls into maas:master
- Git
- lp:~andreserl/maas
- lp1774206_trusted_acls
- Merge into master
Proposed by
Andres Rodriguez
Status: | Merged |
---|---|
Approved by: | Andres Rodriguez |
Approved revision: | 864a786d09f692b7595d26aa4067728d024a61ea |
Merge reported by: | MAAS Lander |
Merged at revision: | not available |
Proposed branch: | ~andreserl/maas:lp1774206_trusted_acls |
Merge into: | maas:master |
Diff against target: |
515 lines (+311/-7) 11 files modified
src/maasserver/dns/config.py (+13/-2) src/maasserver/dns/tests/test_config.py (+40/-0) src/maasserver/fields.py (+64/-0) src/maasserver/forms/__init__.py (+1/-0) src/maasserver/forms/settings.py (+17/-0) src/maasserver/models/config.py (+1/-0) src/maasserver/tests/test_fields.py (+107/-0) src/maasserver/triggers/system.py (+8/-4) src/maasserver/triggers/tests/test_system_listener.py (+52/-0) src/maasserver/views/tests/test_settings.py (+7/-1) src/provisioningserver/dns/actions.py (+1/-0) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
MAAS Lander | Approve | ||
Blake Rouse (community) | Approve | ||
Review via email: mp+347398@code.launchpad.net |
Commit message
LP: #1774206 - Add config option 'dns_trusted_acl'.
MAAS DNS has a 'trusted' ACL that lists the networks that are allowed to use MAAS for DNS resolution. This option allows to specify other networks (or IPs/ACLs) not known to MAAS that can use it for DNS resolution.
Description of the change
To post a comment you must log in.
- 110fdce... by Andres Rodriguez
-
LP: #1774206 - Add ability to add extra items to the 'trusted' ACL
- 864a786... by Andres Rodriguez
-
Fix lint
Revision history for this message
Blake Rouse (blake-rouse) wrote : | # |
Looks good. Well tested to!
review:
Approve
Revision history for this message
MAAS Lander (maas-lander) wrote : | # |
UNIT TESTS
-b lp1774206_
STATUS: SUCCESS
COMMIT: 864a786d09f692b
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/src/maasserver/dns/config.py b/src/maasserver/dns/config.py |
2 | index da2968e..e5dba64 100644 |
3 | --- a/src/maasserver/dns/config.py |
4 | +++ b/src/maasserver/dns/config.py |
5 | @@ -121,15 +121,26 @@ def get_dnssec_validation(): |
6 | return Config.objects.get_config("dnssec_validation") |
7 | |
8 | |
9 | +def get_trusted_acls(): |
10 | + """Return the configuration option for trusted ACLs. |
11 | + |
12 | + :return: A list of CIDR-format subnet, IPs or names. |
13 | + """ |
14 | + items = Config.objects.get_config("dns_trusted_acl") |
15 | + return [] if items is None else items.split() |
16 | + |
17 | + |
18 | def get_trusted_networks(): |
19 | - """Return the CIDR representation of all the Subnets we know about. |
20 | + """Return the CIDR representation of all the subnets we know about |
21 | + combined with the list from get_trusted_acls(). |
22 | |
23 | :return: A list of CIDR-format subnet specifications. |
24 | """ |
25 | - return [ |
26 | + known_subnets = [ |
27 | str(subnet.cidr) |
28 | for subnet in Subnet.objects.all() |
29 | ] |
30 | + return list(set(known_subnets + get_trusted_acls())) |
31 | |
32 | |
33 | def get_resource_name_for_subnet(subnet): |
34 | diff --git a/src/maasserver/dns/tests/test_config.py b/src/maasserver/dns/tests/test_config.py |
35 | index 036c144..cd933fd 100644 |
36 | --- a/src/maasserver/dns/tests/test_config.py |
37 | +++ b/src/maasserver/dns/tests/test_config.py |
38 | @@ -19,6 +19,7 @@ from maasserver.dns.config import ( |
39 | dns_update_all_zones, |
40 | get_internal_domain, |
41 | get_resource_name_for_subnet, |
42 | + get_trusted_acls, |
43 | get_trusted_networks, |
44 | get_upstream_dns, |
45 | ) |
46 | @@ -330,6 +331,17 @@ class TestDNSConfigModifications(TestDNSServer): |
47 | compose_config_path(DNSConfig.target_file_name), |
48 | FileContains(matcher=Contains(trusted_network))) |
49 | |
50 | + def test_dns_update_all_zones_writes_trusted_networks_params_extra(self): |
51 | + self.patch(settings, 'DNS_CONNECT', True) |
52 | + extra_trusted_network = factory.make_ipv6_network() |
53 | + get_trusted_acls_patch = self.patch( |
54 | + dns_config_module, 'get_trusted_acls') |
55 | + get_trusted_acls_patch.return_value = [extra_trusted_network.cidr] |
56 | + dns_update_all_zones() |
57 | + self.assertThat( |
58 | + compose_config_path(DNSConfig.target_file_name), |
59 | + FileContains(matcher=Contains(str(extra_trusted_network)))) |
60 | + |
61 | def test_dns_config_has_NS_record(self): |
62 | self.patch(settings, 'DNS_CONNECT', True) |
63 | ip = factory.make_ipv4_address() |
64 | @@ -443,6 +455,34 @@ class TestGetUpstreamDNS(MAASServerTestCase): |
65 | self.assertEqual(addresses, get_upstream_dns()) |
66 | |
67 | |
68 | +class TestGetTrustedAcls(MAASServerTestCase): |
69 | + """Test for maasserver/dns/config.py:get_trusted_acls()""" |
70 | + |
71 | + def setUp(self): |
72 | + super(TestGetTrustedAcls, self).setUp() |
73 | + self.useFixture(RegionConfigurationFixture()) |
74 | + |
75 | + def test__returns_empty_string_if_no_networks(self): |
76 | + self.assertEqual([], get_trusted_acls()) |
77 | + |
78 | + def test__returns_single_network(self): |
79 | + subnet = factory.make_ipv6_network() |
80 | + Config.objects.set_config('dns_trusted_acl', str(subnet)) |
81 | + expected = [str(subnet)] |
82 | + self.assertEqual(expected, get_trusted_acls()) |
83 | + |
84 | + def test__returns_many_networks(self): |
85 | + subnets = [ |
86 | + str(factory.make_ipv4_network()) for _ in range( |
87 | + random.randint(1, 5))] |
88 | + actual_subnets = ' '.join(subnets) |
89 | + Config.objects.set_config('dns_trusted_acl', str(actual_subnets)) |
90 | + expected = [subnet for subnet in subnets] |
91 | + # Note: This test was seen randomly failing because the networks were |
92 | + # in an unexpected order... |
93 | + self.assertItemsEqual(expected, get_trusted_acls()) |
94 | + |
95 | + |
96 | class TestGetTrustedNetworks(MAASServerTestCase): |
97 | """Test for maasserver/dns/config.py:get_trusted_networks()""" |
98 | |
99 | diff --git a/src/maasserver/fields.py b/src/maasserver/fields.py |
100 | index 2ff9a53..b139fa3 100644 |
101 | --- a/src/maasserver/fields.py |
102 | +++ b/src/maasserver/fields.py |
103 | @@ -690,6 +690,70 @@ class HostListFormField(forms.CharField): |
104 | return host |
105 | |
106 | |
107 | +class SubnetListFormField(forms.CharField): |
108 | + """Accepts a space/comma separated list of hostnames, Subnets or IPs. |
109 | + |
110 | + This field normalizes the list to a space-separated list. |
111 | + """ |
112 | + separators = re.compile('[,\s]+') |
113 | + |
114 | + # Regular expressions to sniff out things that look like IP addresses; |
115 | + # additional and more robust validation ought to be done to make sure. |
116 | + pt_ipv4 = r"(?: \d{1,3} [.] \d{1,3} [.] \d{1,3} [.] \d{1,3} )" |
117 | + pt_ipv6 = r"(?: (|[0-9A-Fa-f]{1,4}) [:] (|[0-9A-Fa-f]{1,4}) [:] (.*))" |
118 | + pt_ip = re.compile( |
119 | + r"^ (?: %s | %s ) $" % (pt_ipv4, pt_ipv6), re.VERBOSE) |
120 | + pt_subnet = re.compile( |
121 | + r"^ (?: %s | %s ) \/\d+$" % (pt_ipv4, pt_ipv6), re.VERBOSE) |
122 | + |
123 | + def clean(self, value): |
124 | + if value is None: |
125 | + return None |
126 | + else: |
127 | + values = map(str.strip, self.separators.split(value)) |
128 | + values = (value for value in values if len(value) != 0) |
129 | + values = map(self._clean_addr_or_host, values) |
130 | + return ' '.join(values) |
131 | + |
132 | + def _clean_addr_or_host(self, value): |
133 | + looks_like_ip = self.pt_ip.match(value) is not None |
134 | + looks_like_subnet = self.pt_subnet.match(value) is not None |
135 | + if looks_like_subnet: |
136 | + return self._clean_subnet(value) |
137 | + elif looks_like_ip: |
138 | + return self._clean_addr(value) |
139 | + else: |
140 | + return self._clean_host(value) |
141 | + |
142 | + def _clean_addr(self, value): |
143 | + try: |
144 | + addr = IPAddress(value) |
145 | + except ValueError: |
146 | + return |
147 | + except AddrFormatError as error: |
148 | + raise ValidationError( |
149 | + "Invalid IP address: %s." % value) |
150 | + else: |
151 | + return str(addr) |
152 | + |
153 | + def _clean_subnet(self, value): |
154 | + try: |
155 | + cidr = IPNetwork(value) |
156 | + except AddrFormatError: |
157 | + raise ValidationError( |
158 | + "Invalid network: %s." % value) |
159 | + else: |
160 | + return str(cidr) |
161 | + |
162 | + def _clean_host(self, host): |
163 | + try: |
164 | + validate_hostname(host) |
165 | + except ValidationError as error: |
166 | + raise ValidationError("Invalid hostname: " + error.message) |
167 | + else: |
168 | + return host |
169 | + |
170 | + |
171 | class CaseInsensitiveChoiceField(forms.ChoiceField): |
172 | """ChoiceField that allows the input to be case insensitive.""" |
173 | |
174 | diff --git a/src/maasserver/forms/__init__.py b/src/maasserver/forms/__init__.py |
175 | index 6c20906..52939a3 100644 |
176 | --- a/src/maasserver/forms/__init__.py |
177 | +++ b/src/maasserver/forms/__init__.py |
178 | @@ -1501,6 +1501,7 @@ class DNSForm(ConfigForm): |
179 | """Settings page, DNS section.""" |
180 | upstream_dns = get_config_field('upstream_dns') |
181 | dnssec_validation = get_config_field('dnssec_validation') |
182 | + dns_trusted_acl = get_config_field('dns_trusted_acl') |
183 | |
184 | |
185 | class NTPForm(ConfigForm): |
186 | diff --git a/src/maasserver/forms/settings.py b/src/maasserver/forms/settings.py |
187 | index 0420b33..a6ce778 100644 |
188 | --- a/src/maasserver/forms/settings.py |
189 | +++ b/src/maasserver/forms/settings.py |
190 | @@ -21,6 +21,7 @@ from maasserver.bootresources import IMPORT_RESOURCES_SERVICE_PERIOD |
191 | from maasserver.fields import ( |
192 | HostListFormField, |
193 | IPListFormField, |
194 | + SubnetListFormField, |
195 | ) |
196 | from maasserver.models import BootResource |
197 | from maasserver.models.config import ( |
198 | @@ -357,6 +358,22 @@ CONFIG_ITEMS = { |
199 | "provided by the set upstream DNS.") |
200 | } |
201 | }, |
202 | + 'dns_trusted_acl': { |
203 | + 'default': None, |
204 | + 'form': SubnetListFormField, |
205 | + 'form_kwargs': { |
206 | + 'label': ( |
207 | + "List of external networks (not previously known), that will " |
208 | + "be allowed to use MAAS for DNS resolution."), |
209 | + 'required': False, |
210 | + 'help_text': ( |
211 | + "MAAS keeps a list of networks that are allowed to use MAAS " |
212 | + "for DNS resolution. This option allows to add extra " |
213 | + "networks (not previously known) to the trusted ACL where " |
214 | + "this list of networks is kept. It also supports specifying " |
215 | + "IPs or ACL names.") |
216 | + } |
217 | + }, |
218 | 'ntp_servers': { |
219 | 'default': None, |
220 | 'form': HostListFormField, |
221 | diff --git a/src/maasserver/models/config.py b/src/maasserver/models/config.py |
222 | index 4c86449..914313f 100644 |
223 | --- a/src/maasserver/models/config.py |
224 | +++ b/src/maasserver/models/config.py |
225 | @@ -78,6 +78,7 @@ def get_default_config(): |
226 | # DNS settings |
227 | 'upstream_dns': None, |
228 | 'dnssec_validation': "auto", |
229 | + 'dns_trusted_acl': None, |
230 | 'maas_internal_domain': 'maas-internal', |
231 | # NTP settings |
232 | 'ntp_servers': 'ntp.ubuntu.com', |
233 | diff --git a/src/maasserver/tests/test_fields.py b/src/maasserver/tests/test_fields.py |
234 | index 10addd9..ffaab8e 100644 |
235 | --- a/src/maasserver/tests/test_fields.py |
236 | +++ b/src/maasserver/tests/test_fields.py |
237 | @@ -29,6 +29,7 @@ from maasserver.fields import ( |
238 | MODEL_NAME_VALIDATOR, |
239 | NodeChoiceField, |
240 | register_mac_type, |
241 | + SubnetListFormField, |
242 | URLOrPPAFormField, |
243 | URLOrPPAValidator, |
244 | validate_mac, |
245 | @@ -705,6 +706,112 @@ class TestNodeChoiceField(MAASServerTestCase): |
246 | self.assertEqual(node, node_field.clean(node.system_id)) |
247 | |
248 | |
249 | +class TestSubnetListFormField(MAASTestCase): |
250 | + |
251 | + def test_accepts_none(self): |
252 | + self.assertIsNone(SubnetListFormField().clean(None)) |
253 | + |
254 | + def test_accepts_single_ip(self): |
255 | + ip = factory.make_ip_address() |
256 | + self.assertEqual(ip, SubnetListFormField().clean(ip)) |
257 | + |
258 | + def test_accepts_space_separated_ips(self): |
259 | + ips = [factory.make_ip_address() for _ in range(5)] |
260 | + input = ' '.join(ips) |
261 | + self.assertEqual(input, SubnetListFormField().clean(input)) |
262 | + |
263 | + def test_accepts_comma_separated_ips(self): |
264 | + ips = [factory.make_ip_address() for _ in range(5)] |
265 | + input = ','.join(ips) |
266 | + self.assertEqual(' '.join(ips), SubnetListFormField().clean(input)) |
267 | + |
268 | + def test_accepts_single_subnet(self): |
269 | + subnet = str(factory.make_ipv4_network()) |
270 | + self.assertEqual(subnet, SubnetListFormField().clean(subnet)) |
271 | + |
272 | + def test_accepts_space_separated_subnets(self): |
273 | + subnets = [str(factory.make_ipv6_network()) for _ in range(5)] |
274 | + input = ' '.join(subnets) |
275 | + self.assertEqual(input, SubnetListFormField().clean(input)) |
276 | + |
277 | + def test_accepts_comma_separated_subnets(self): |
278 | + subnets = [str(factory.make_ipv4_network()) for _ in range(5)] |
279 | + input = ','.join(subnets) |
280 | + self.assertEqual(' '.join(subnets), SubnetListFormField().clean(input)) |
281 | + |
282 | + def test_separators_dont_conflict_with_ipv4_address(self): |
283 | + self.assertIsNone(re.search( |
284 | + SubnetListFormField.separators, factory.make_ipv4_address())) |
285 | + |
286 | + def test_separators_dont_conflict_with_ipv6_address(self): |
287 | + self.assertIsNone(re.search( |
288 | + SubnetListFormField.separators, factory.make_ipv6_address())) |
289 | + |
290 | + def test_accepts_hostname(self): |
291 | + hostname = factory.make_hostname() |
292 | + self.assertEqual(hostname, SubnetListFormField().clean(hostname)) |
293 | + |
294 | + def test_accepts_space_separated_hostnames(self): |
295 | + hostnames = factory.make_hostname(), factory.make_hostname() |
296 | + input = ' '.join(hostnames) |
297 | + self.assertEqual(input, SubnetListFormField().clean(input)) |
298 | + |
299 | + def test_accepts_comma_separated_hostnames(self): |
300 | + hostnames = factory.make_hostname(), factory.make_hostname() |
301 | + input = ','.join(hostnames) |
302 | + self.assertEqual( |
303 | + ' '.join(hostnames), SubnetListFormField().clean(input)) |
304 | + |
305 | + def test_accepts_misc(self): |
306 | + servers = { |
307 | + "::1", |
308 | + "1::", |
309 | + "1::2", |
310 | + "1:2::3", |
311 | + "1::2:3", |
312 | + "1:2::3:4", |
313 | + "::127.0.0.1", |
314 | + } |
315 | + input = ','.join(servers) |
316 | + self.assertEqual(' '.join(servers), SubnetListFormField().clean(input)) |
317 | + |
318 | + def test_rejects_invalid_ipv4_address(self): |
319 | + input = "%s 12.34.56.999" % factory.make_hostname() |
320 | + error = self.assertRaises( |
321 | + ValidationError, SubnetListFormField().clean, input) |
322 | + self.assertThat(error.message, Equals( |
323 | + "Invalid IP address: 12.34.56.999.")) |
324 | + |
325 | + def test_rejects_invalid_ipv6_address(self): |
326 | + input = "%s fe80::abcde" % factory.make_hostname() |
327 | + error = self.assertRaises( |
328 | + ValidationError, SubnetListFormField().clean, input) |
329 | + self.assertThat(error.message, Equals( |
330 | + "Invalid IP address: fe80::abcde.")) |
331 | + |
332 | + def test_rejects_invalid_ipv4_subnet(self): |
333 | + input = "%s 10.10.10.300/24" % factory.make_ipv4_network() |
334 | + error = self.assertRaises( |
335 | + ValidationError, SubnetListFormField().clean, input) |
336 | + self.assertThat(error.message, Equals( |
337 | + "Invalid network: 10.10.10.300/24.")) |
338 | + |
339 | + def test_rejects_invalid_ipv6_subnet(self): |
340 | + input = "%s 100::/300" % factory.make_ipv6_network() |
341 | + error = self.assertRaises( |
342 | + ValidationError, SubnetListFormField().clean, input) |
343 | + self.assertThat(error.message, Equals( |
344 | + "Invalid network: 100::/300.")) |
345 | + |
346 | + def test_rejects_invalid_hostname(self): |
347 | + input = "%s abc-.foo" % factory.make_hostname() |
348 | + error = self.assertRaises( |
349 | + ValidationError, SubnetListFormField().clean, input) |
350 | + self.assertThat(error.message, Equals( |
351 | + "Invalid hostname: Label cannot start or end with " |
352 | + "hyphen: 'abc-'.")) |
353 | + |
354 | + |
355 | class TestVersionedTextFileField(MAASServerTestCase): |
356 | |
357 | def test_creates_new(self): |
358 | diff --git a/src/maasserver/triggers/system.py b/src/maasserver/triggers/system.py |
359 | index d6df1d6..1db361c 100644 |
360 | --- a/src/maasserver/triggers/system.py |
361 | +++ b/src/maasserver/triggers/system.py |
362 | @@ -1335,8 +1335,8 @@ DNS_INTERFACE_UPDATE = dedent("""\ |
363 | |
364 | # Triggered when a config is inserted. Increments the zone serial and notifies |
365 | # that DNS needs to be updated. Only watches for inserts on config |
366 | -# upstream_dns, dnssec_validation, default_dns_ttl, windows_kms_host, and |
367 | -# maas_internal_domain. |
368 | +# upstream_dns, dnssec_validation, default_dns_ttl, windows_kms_host, |
369 | +# dns_trusted_acls and maas_internal_domain. |
370 | DNS_CONFIG_INSERT = dedent("""\ |
371 | CREATE OR REPLACE FUNCTION sys_dns_config_insert() |
372 | RETURNS trigger as $$ |
373 | @@ -1344,6 +1344,7 @@ DNS_CONFIG_INSERT = dedent("""\ |
374 | -- Only care about the |
375 | IF (NEW.name = 'upstream_dns' OR |
376 | NEW.name = 'dnssec_validation' OR |
377 | + NEW.name = 'dns_trusted_acl' OR |
378 | NEW.name = 'default_dns_ttl' OR |
379 | NEW.name = 'windows_kms_host' OR |
380 | NEW.name = 'maas_internal_domain') |
381 | @@ -1359,15 +1360,18 @@ DNS_CONFIG_INSERT = dedent("""\ |
382 | |
383 | # Triggered when a config is updated. Increments the zone serial and notifies |
384 | # that DNS needs to be updated. Only watches for updates on config |
385 | -# upstream_dns, dnssec_validation, default_dns_ttl, and windows_kms_host. |
386 | +# upstream_dns, dnssec_validation, dns_trusted_acl, default_dns_ttl, |
387 | +# and windows_kms_host. |
388 | DNS_CONFIG_UPDATE = dedent("""\ |
389 | CREATE OR REPLACE FUNCTION sys_dns_config_update() |
390 | RETURNS trigger as $$ |
391 | BEGIN |
392 | - -- Only care about the |
393 | + -- Only care about the upstream_dns, default_dns_ttl, |
394 | + -- dns_trusted_acl and windows_kms_host. |
395 | IF (OLD.value != NEW.value AND ( |
396 | NEW.name = 'upstream_dns' OR |
397 | NEW.name = 'dnssec_validation' OR |
398 | + NEW.name = 'dns_trusted_acl' OR |
399 | NEW.name = 'default_dns_ttl' OR |
400 | NEW.name = 'windows_kms_host' OR |
401 | NEW.name = 'maas_internal_domain')) |
402 | diff --git a/src/maasserver/triggers/tests/test_system_listener.py b/src/maasserver/triggers/tests/test_system_listener.py |
403 | index d00dd83..072f082 100644 |
404 | --- a/src/maasserver/triggers/tests/test_system_listener.py |
405 | +++ b/src/maasserver/triggers/tests/test_system_listener.py |
406 | @@ -4218,6 +4218,30 @@ class TestDNSConfigListener( |
407 | |
408 | @wait_for_reactor |
409 | @inlineCallbacks |
410 | + def test_sends_message_for_config_dns_trusted_acl_insert(self): |
411 | + dns_trusted_acl_new = factory.make_name('internal') |
412 | + yield deferToDatabase(register_system_triggers) |
413 | + yield self.capturePublication() |
414 | + dv = DeferredValue() |
415 | + listener = self.make_listener_without_delay() |
416 | + listener.register( |
417 | + "sys_dns", lambda *args: dv.set(args)) |
418 | + yield listener.startService() |
419 | + try: |
420 | + yield deferToDatabase( |
421 | + Config.objects.set_config, |
422 | + "dns_trusted_acl", dns_trusted_acl_new) |
423 | + yield dv.get(timeout=2) |
424 | + yield self.assertPublicationUpdated() |
425 | + finally: |
426 | + yield listener.stopService() |
427 | + self.assertThat( |
428 | + self.getCapturedPublication().source, Equals( |
429 | + "configuration dns_trusted_acl set to %s" |
430 | + % json.dumps(dns_trusted_acl_new))) |
431 | + |
432 | + @wait_for_reactor |
433 | + @inlineCallbacks |
434 | def test_sends_message_for_config_upstream_dns_update(self): |
435 | upstream_dns_old = factory.make_ip_address() |
436 | upstream_dns_new = factory.make_ip_address() |
437 | @@ -4326,6 +4350,34 @@ class TestDNSConfigListener( |
438 | "configuration maas_internal_domain changed to %s" |
439 | % (json.dumps(maas_internal_domain_new)))) |
440 | |
441 | + @wait_for_reactor |
442 | + @inlineCallbacks |
443 | + def test_sends_message_for_config_dns_trusted_acl_update(self): |
444 | + dns_trusted_acl_old = factory.make_name('internal') |
445 | + dns_trusted_acl_new = factory.make_name('internal_new') |
446 | + yield deferToDatabase(register_system_triggers) |
447 | + yield deferToDatabase( |
448 | + Config.objects.set_config, |
449 | + "dns_trusted_acl", dns_trusted_acl_old) |
450 | + yield self.capturePublication() |
451 | + dv = DeferredValue() |
452 | + listener = self.make_listener_without_delay() |
453 | + listener.register( |
454 | + "sys_dns", lambda *args: dv.set(args)) |
455 | + yield listener.startService() |
456 | + try: |
457 | + yield deferToDatabase( |
458 | + Config.objects.set_config, |
459 | + "dns_trusted_acl", dns_trusted_acl_new) |
460 | + yield dv.get(timeout=2) |
461 | + yield self.assertPublicationUpdated() |
462 | + finally: |
463 | + yield listener.stopService() |
464 | + self.assertThat( |
465 | + self.getCapturedPublication().source, Equals( |
466 | + "configuration dns_trusted_acl changed to %s" |
467 | + % (json.dumps(dns_trusted_acl_new)))) |
468 | + |
469 | |
470 | class TestDNSConfigListenerLegacy( |
471 | MAASLegacyTransactionServerTestCase, TransactionalHelpersMixin, |
472 | diff --git a/src/maasserver/views/tests/test_settings.py b/src/maasserver/views/tests/test_settings.py |
473 | index 392a84e..5670b18 100644 |
474 | --- a/src/maasserver/views/tests/test_settings.py |
475 | +++ b/src/maasserver/views/tests/test_settings.py |
476 | @@ -180,7 +180,10 @@ class SettingsTest(MAASServerTestCase): |
477 | self.addCleanup(bootsources.signals.enable) |
478 | bootsources.signals.disable() |
479 | self.client.login(user=factory.make_admin()) |
480 | - new_upstream = "8.8.8.8" |
481 | + new_upstream = "8.8.8.8 8.8.4.4" |
482 | + new_ipv4_subnet = factory.make_ipv4_network() |
483 | + new_ipv6_subnet = factory.make_ipv6_network() |
484 | + new_subnets = "%s %s" % (new_ipv4_subnet, new_ipv6_subnet) |
485 | response = self.client.post( |
486 | reverse('settings_network'), |
487 | get_prefixed_form_data( |
488 | @@ -188,12 +191,15 @@ class SettingsTest(MAASServerTestCase): |
489 | data={ |
490 | 'upstream_dns': new_upstream, |
491 | 'dnssec_validation': 'no', |
492 | + 'dns_trusted_acl': new_subnets, |
493 | })) |
494 | self.assertEqual( |
495 | http.client.FOUND, response.status_code, response.content) |
496 | self.assertEqual( |
497 | new_upstream, Config.objects.get_config('upstream_dns')) |
498 | self.assertEqual('no', Config.objects.get_config('dnssec_validation')) |
499 | + self.assertEqual( |
500 | + new_subnets, Config.objects.get_config('dns_trusted_acl')) |
501 | |
502 | def test_settings_ntp_POST(self): |
503 | # Disable boot source cache signals. |
504 | diff --git a/src/provisioningserver/dns/actions.py b/src/provisioningserver/dns/actions.py |
505 | index 97ad042..a955023 100644 |
506 | --- a/src/provisioningserver/dns/actions.py |
507 | +++ b/src/provisioningserver/dns/actions.py |
508 | @@ -123,6 +123,7 @@ def bind_write_options(upstream_dns, dnssec_validation): |
509 | """Write BIND options. |
510 | |
511 | :param upstream_dns: A sequence of upstream DNS servers. |
512 | + :param dnssec_validation: Whether to enable DNSSec. |
513 | """ |
514 | # upstream_dns was formerly specified as a single IP address. These |
515 | # assertions are here to prevent code that assumes that slipping through. |
UNIT TESTS trusted_ acls lp:~andreserl/maas/+git/maas into -b master lp:~maas-committers/maas
-b lp1774206_
STATUS: FAILED maas-ci- jenkins. internal: 8080/job/ maas/job/ branch- tester/ 3586/console fccf19ebc5784ea 63a6e97f46
LOG: http://
COMMIT: 4de9e12c92cac6a