Merge lp:~rvb/maas/maas-forwarders-1.8 into lp:maas/1.8

Proposed by Raphaël Badin
Status: Merged
Approved by: Raphaël Badin
Approved revision: no longer in the source branch.
Merged at revision: 4016
Proposed branch: lp:~rvb/maas/maas-forwarders-1.8
Merge into: lp:maas/1.8
Diff against target: 196 lines (+81/-9)
5 files modified
src/maasserver/dns/tests/test_config.py (+8/-6)
src/maasserver/fields.py (+25/-1)
src/maasserver/forms_settings.py (+3/-2)
src/maasserver/tests/test_fields.py (+37/-0)
src/maasserver/tests/test_forms_settings.py (+8/-0)
To merge this branch: bzr merge lp:~rvb/maas/maas-forwarders-1.8
Reviewer Review Type Date Requested Status
Gavin Panella (community) Approve
Review via email: mp+263748@code.launchpad.net

Commit message

Backport 4062: upstream_dns: accept a list of forwarders (and not just *one* forwarder).

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

I know this is a back-port even though I've reviewed it like a new change. There's nothing in here that I think should prevent landing at all, but I have a number of comments anyway.

review: Approve
Revision history for this message
Mike Pontillo (mpontillo) wrote :

A couple quick comments.

Revision history for this message
Raphaël Badin (rvb) wrote :

Thanks for the review. I'll forward port the fixes made here to trunk.

Revision history for this message
MAAS Lander (maas-lander) wrote :

There are additional revisions which have not been approved in review. Please seek review and approval of these new revisions.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/maasserver/dns/tests/test_config.py'
2--- src/maasserver/dns/tests/test_config.py 2015-05-16 06:21:20 +0000
3+++ src/maasserver/dns/tests/test_config.py 2015-07-06 08:31:26 +0000
4@@ -496,15 +496,16 @@
5 def test_dns_update_all_zones_now_passes_upstream_dns_parameter(self):
6 self.patch(settings, 'DNS_CONNECT', True)
7 self.create_managed_nodegroup()
8- random_ip = factory.make_ipv4_address()
9- Config.objects.set_config("upstream_dns", random_ip)
10+ ips = [factory.make_ipv4_address() for _ in range(3)]
11+ input_ips = " ".join(ips)
12+ Config.objects.set_config("upstream_dns", input_ips)
13 bind_write_options = self.patch_autospec(
14 dns_config_module, "bind_write_options")
15 dns_update_all_zones_now()
16 self.assertThat(
17 bind_write_options,
18 MockCalledOnceWith(
19- dnssec_validation='auto', upstream_dns=[random_ip]))
20+ dnssec_validation='auto', upstream_dns=ips))
21
22 def test_dns_update_all_zones_now_writes_trusted_networks_parameter(self):
23 self.patch(settings, 'DNS_CONNECT', True)
24@@ -667,12 +668,13 @@
25 self.assertEqual([], get_upstream_dns())
26
27 def test__returns_list_of_one_address_if_set(self):
28- address = factory.make_ipv4_address()
29+ address = factory.make_ip_address()
30 Config.objects.set_config("upstream_dns", address)
31 self.assertEqual([address], get_upstream_dns())
32
33- def test__returns_list_of_many_address_if_set(self):
34- addresses = [factory.make_ipv4_address(), factory.make_ipv4_address()]
35+ def test__returns_list_if_space_separated_ips(self):
36+ addresses = [
37+ factory.make_ip_address() for _ in range(3)]
38 Config.objects.set_config("upstream_dns", " ".join(addresses))
39 self.assertEqual(addresses, get_upstream_dns())
40
41
42=== modified file 'src/maasserver/fields.py'
43--- src/maasserver/fields.py 2015-05-13 11:33:20 +0000
44+++ src/maasserver/fields.py 2015-07-06 08:31:26 +0000
45@@ -1,7 +1,7 @@
46 # Copyright 2012-2015 Canonical Ltd. This software is licensed under the
47 # GNU Affero General Public License version 3 (see the file LICENSE).
48
49-"""Custom model fields."""
50+"""Custom model and form fields."""
51
52 from __future__ import (
53 absolute_import,
54@@ -14,6 +14,7 @@
55 __metaclass__ = type
56 __all__ = [
57 "EditableBinaryField",
58+ "IPListFormField",
59 "MAASIPAddressField",
60 "MAC",
61 "MACAddressField",
62@@ -532,3 +533,26 @@
63 raise AssertionError(
64 "Invalid LargeObjectField value (expected integer): '%s'"
65 % repr(value))
66+
67+
68+class IPListFormField(CharField):
69+ """Accepts a space/comma separated list of IP addresses.
70+
71+ This field normalizes the list to a space-separated list.
72+ """
73+ separators = re.compile('[,\s]+')
74+
75+ def clean(self, value):
76+ if value is None:
77+ return None
78+ else:
79+ ips = re.split(self.separators, value)
80+ ips = [ip.strip() for ip in ips if ip != '']
81+ for ip in ips:
82+ try:
83+ GenericIPAddressField().clean(ip, model_instance=None)
84+ except ValidationError:
85+ raise ValidationError(
86+ "Invalid IP address: %s; provide a list of "
87+ "space-separated IP addresses" % ip)
88+ return ' '.join(ips)
89
90=== modified file 'src/maasserver/forms_settings.py'
91--- src/maasserver/forms_settings.py 2015-06-04 14:31:33 +0000
92+++ src/maasserver/forms_settings.py 2015-07-06 08:31:26 +0000
93@@ -26,6 +26,7 @@
94 from django import forms
95 from django.core.exceptions import ValidationError
96 from maasserver.bootresources import IMPORT_RESOURCES_SERVICE_PERIOD
97+from maasserver.fields import IPListFormField
98 from maasserver.models.config import (
99 Config,
100 DEFAULT_OS,
101@@ -180,11 +181,11 @@
102 },
103 'upstream_dns': {
104 'default': None,
105- 'form': forms.GenericIPAddressField,
106+ 'form': IPListFormField,
107 'form_kwargs': {
108 'label': (
109 "Upstream DNS used to resolve domains not managed by this "
110- "MAAS"),
111+ "MAAS (space-separated IP addresses)"),
112 'required': False,
113 'help_text': (
114 "Only used when MAAS is running its own DNS server. This "
115
116=== modified file 'src/maasserver/tests/test_fields.py'
117--- src/maasserver/tests/test_fields.py 2015-05-07 18:14:38 +0000
118+++ src/maasserver/tests/test_fields.py 2015-07-06 08:31:26 +0000
119@@ -16,6 +16,7 @@
120
121 import json
122 from random import randint
123+import re
124
125 from django.core import serializers
126 from django.core.exceptions import ValidationError
127@@ -27,6 +28,7 @@
128 from maasserver.enum import NODEGROUPINTERFACE_MANAGEMENT
129 from maasserver.fields import (
130 EditableBinaryField,
131+ IPListFormField,
132 LargeObjectField,
133 LargeObjectFile,
134 MAC,
135@@ -518,3 +520,38 @@
136 field = LargeObjectField()
137 self.assertRaises(
138 AssertionError, field.to_python, factory.make_string())
139+
140+
141+class IPListFormFieldTest(MAASServerTestCase):
142+
143+ def test_accepts_none(self):
144+ self.assertIsNone(IPListFormField().clean(None))
145+
146+ def test_accepts_single_ip(self):
147+ ip = factory.make_ip_address()
148+ self.assertEquals(ip, IPListFormField().clean(ip))
149+
150+ def test_accepts_space_separated_ips(self):
151+ ips = [factory.make_ip_address() for _ in range(5)]
152+ input = ' '.join(ips)
153+ self.assertEquals(input, IPListFormField().clean(input))
154+
155+ def test_accepts_comma_separated_ips(self):
156+ ips = [factory.make_ip_address() for _ in range(5)]
157+ input = ','.join(ips)
158+ self.assertEquals(' '.join(ips), IPListFormField().clean(input))
159+
160+ def test_rejects_invalid_input(self):
161+ invalid = factory.make_name('invalid')
162+ input = ' '.join([factory.make_ip_address(), invalid])
163+ error = self.assertRaises(
164+ ValidationError, IPListFormField().clean, input)
165+ self.assertIn("Invalid IP address: %s" % invalid, error.message)
166+
167+ def test_separators_dont_conflict_with_ipv4_address(self):
168+ self.assertIsNone(re.search(
169+ IPListFormField.separators, factory.make_ipv4_address()))
170+
171+ def test_separators_dont_conflict_with_ipv6_address(self):
172+ self.assertIsNone(re.search(
173+ IPListFormField.separators, factory.make_ipv6_address()))
174
175=== modified file 'src/maasserver/tests/test_forms_settings.py'
176--- src/maasserver/tests/test_forms_settings.py 2015-05-07 18:14:38 +0000
177+++ src/maasserver/tests/test_forms_settings.py 2015-07-06 08:31:26 +0000
178@@ -14,6 +14,7 @@
179 __metaclass__ = type
180 __all__ = []
181
182+
183 from django import forms
184 from maasserver.forms_settings import (
185 CONFIG_ITEMS,
186@@ -70,3 +71,10 @@
187 compose_invalid_choice_text(
188 'commissioning_distro_series', field.choices),
189 field.error_messages['invalid_choice'])
190+
191+ def test_upstream_dns_accepts_ip_list(self):
192+ field = get_config_field('upstream_dns')
193+ ips1 = [factory.make_ip_address() for _ in range(3)]
194+ ips2 = [factory.make_ip_address() for _ in range(3)]
195+ input = ' '.join(ips1) + ' ' + ','.join(ips2)
196+ self.assertEqual(' '.join(ips1 + ips2), field.clean(input))

Subscribers

People subscribed via source and target branches