Merge ~ddstreet/maas:lp1896684 into maas:master

Proposed by Dan Streetman
Status: Merged
Approved by: Lee Trager
Approved revision: b60e8e96657ffce7939970ad8a911042888114cc
Merge reported by: MAAS Lander
Merged at revision: not available
Proposed branch: ~ddstreet/maas:lp1896684
Merge into: maas:master
Diff against target: 364 lines (+158/-43)
6 files modified
src/maasserver/dhcp.py (+13/-1)
src/maasserver/models/node.py (+6/-11)
src/maasserver/models/tests/test_node.py (+20/-0)
src/maasserver/preseed_network.py (+26/-21)
src/maasserver/tests/test_dhcp.py (+44/-10)
src/maasserver/tests/test_preseed_network.py (+49/-0)
Reviewer Review Type Date Requested Status
Lee Trager (community) Approve
MAAS Lander Approve
Dan Streetman (community) Needs Resubmitting
Review via email: mp+391198@code.launchpad.net

Commit message

LP: #1896684 - If no subnet gateway, only use in-subnet dns addresses

If DHCP is not providing any gateway, it should not provide any
DNS server addresses that aren't directly reachable.

Similarly, if the network preseed is not configuring any gateway,
it should not provide per-interface DNS server addresses, nor default
dns server addresses, that aren't directly reachable.

Only apply rack DNS server address if subnet.allow_dns == True

To post a comment you must log in.
Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b lp1896684 lp:~ddstreet/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: FAILED
LOG: http://maas-ci.internal:8080/job/maas/job/branch-tester/8418/console
COMMIT: 69acdb0067cf0a7159a34678f824f59651750e5b

review: Needs Fixing
Revision history for this message
Dan Streetman (ddstreet) wrote :

> STATUS: FAILED
> LOG: http://maas-ci.internal:8080/job/maas/job/branch-tester/8418/console

I'm not able to access this CI test system to see the logs.

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

UNIT TESTS
-b lp1896684 lp:~ddstreet/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: FAILED
LOG: http://maas-ci.internal:8080/job/maas/job/branch-tester/8419/console
COMMIT: 99132e5871c0a99448db0db8ad59cb612c7f1b2b

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

UNIT TESTS
-b lp1896684 lp:~ddstreet/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: SUCCESS
COMMIT: fdc4a764ddd43050b749df10a2a749437146ba3c

review: Approve
Revision history for this message
Lee Trager (ltrager) wrote :

Thanks for finding and fixing this!

This seems to fix the bug for static IP address, have you tested DHCP? Looking at the code[1] I think its correct but it would be good to verify. Couple of other things

1. This needs commit message to land. It should start with "LP: #1896684 - "
2. Unit tests need to be added to ensure we don't regress this.
3. One comment inline below.

[1] https://git.launchpad.net/maas/tree/src/maasserver/dhcp.py#n420

review: Needs Fixing
~ddstreet/maas:lp1896684 updated
bae3958... by Dan Streetman

LP: #1896684 - If no subnet gateway, only use in-subnet dns addresses

If DHCP is not providing any gateway, it should not provide any
DNS server addresses that aren't directly reachable.

Similarly, if the network preseed is not configuring any gateway,
it should not provide per-interface DNS server addresses, nor default
dns server addresses, that aren't directly reachable.

Revision history for this message
Dan Streetman (ddstreet) wrote :

> Thanks for finding and fixing this!
>
> This seems to fix the bug for static IP address, have you tested DHCP? Looking
> at the code[1] I think its correct but it would be good to verify.

It does look like it needed a change, i included that in the latest patch

> Couple of
> other things
>
> 1. This needs commit message to land. It should start with "LP: #1896684 - "

ok, done

> 2. Unit tests need to be added to ensure we don't regress this.

if these changes look ok to you, i'll work on adding unit tests for them

> 3. One comment inline below.

response inline (with the old diff) - basically i'm confused as to why there's a in-vlan restriction but no in-subnet restriction, without a gateway (or defined route) a node can't access a separate subnet, even if it's in the same vlan. and with a gateway (or defined route), there's no need for the separate subnet to be in the same vlan.

>
>
> [1] https://git.launchpad.net/maas/tree/src/maasserver/dhcp.py#n420

Revision history for this message
Dan Streetman (ddstreet) :
review: Needs Resubmitting
Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b lp1896684 lp:~ddstreet/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: FAILED
LOG: http://maas-ci.internal:8080/job/maas/job/branch-tester/8426/console
COMMIT: f5485d47b0aef19c9454d1d62d265a28fbdef0d5

review: Needs Fixing
Revision history for this message
Lee Trager (ltrager) wrote :

That looks good but this still needs unit tests. Also LaunchPad requires the commit message be added on LaunchPad, it doesn't automatically take whats in git.

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

UNIT TESTS
-b lp1896684 lp:~ddstreet/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: FAILED
LOG: http://maas-ci.internal:8080/job/maas/job/branch-tester/8438/console
COMMIT: 692f3ca6b93e20fcb26c5c9f4e083b3afe86bd19

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

UNIT TESTS
-b lp1896684 lp:~ddstreet/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: FAILED
LOG: http://maas-ci.internal:8080/job/maas/job/branch-tester/8440/console
COMMIT: 44003e8d41e36812a7b4b0df45650e494c809f69

review: Needs Fixing
~ddstreet/maas:lp1896684 updated
b60e8e9... by Dan Streetman

add unit tests

Revision history for this message
Dan Streetman (ddstreet) wrote :

updated commits, and added test cases...let's see if it passes jenkins

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

UNIT TESTS
-b lp1896684 lp:~ddstreet/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: FAILED
LOG: http://maas-ci.internal:8080/job/maas/job/branch-tester/8450/console
COMMIT: d74a74e14352697d4bab6e799546978c991e3663

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

UNIT TESTS
-b lp1896684 lp:~ddstreet/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: FAILED
LOG: http://maas-ci.internal:8080/job/maas/job/branch-tester/8451/console
COMMIT: 82b401ad22dd3298d69eb00a2934c2979e07af09

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

UNIT TESTS
-b lp1896684 lp:~ddstreet/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: SUCCESS
COMMIT: 5e806d38e90f341cc86acb4bb89974b84c63124e

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

UNIT TESTS
-b lp1896684 lp:~ddstreet/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: SUCCESS
COMMIT: b60e8e96657ffce7939970ad8a911042888114cc

review: Approve
Revision history for this message
Lee Trager (ltrager) wrote :

LGTM! Thanks for the fix!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/src/maasserver/dhcp.py b/src/maasserver/dhcp.py
2index 848ff1b..05e9f7a 100644
3--- a/src/maasserver/dhcp.py
4+++ b/src/maasserver/dhcp.py
5@@ -438,7 +438,15 @@ def make_subnet_config(
6 dns_servers = []
7 if subnet.allow_dns and default_dns_servers:
8 # If the MAAS DNS server is enabled make sure that is used first.
9- dns_servers += default_dns_servers
10+ if subnet.gateway_ip:
11+ dns_servers += default_dns_servers
12+ else:
13+ # if there is no gateway, only provide in-subnet dns servers
14+ dns_servers += [
15+ ipaddress
16+ for ipaddress in default_dns_servers
17+ if ipaddress in ip_network
18+ ]
19 if subnet.dns_servers:
20 # Add DNS user defined DNS servers
21 dns_servers += [IPAddress(server) for server in subnet.dns_servers]
22@@ -557,6 +565,10 @@ def get_default_dns_servers(rack_controller, subnet, use_rack_proxy=True):
23 :param use_rack_proxy: Whether to proxy DNS through the rack controller
24 or not.
25 """
26+ if not subnet.allow_dns:
27+ # This subnet isn't allowed to use region or rack addresses for dns
28+ return []
29+
30 ip_version = subnet.get_ip_version()
31 default_region_ip = get_source_address(subnet.get_ipnetwork())
32 try:
33diff --git a/src/maasserver/models/node.py b/src/maasserver/models/node.py
34index d3e40c2..4882eec 100644
35--- a/src/maasserver/models/node.py
36+++ b/src/maasserver/models/node.py
37@@ -4937,6 +4937,8 @@ class Node(CleanSave, TimestampedModel):
38 if ipv4 and gateways.ipv4 is not None:
39 subnet = Subnet.objects.get(id=gateways.ipv4.subnet_id)
40 if subnet.dns_servers:
41+ if not subnet.allow_dns:
42+ return subnet.dns_servers
43 rack_dns = []
44 for rack in {
45 self.get_boot_primary_rack_controller(),
46@@ -4963,6 +4965,8 @@ class Node(CleanSave, TimestampedModel):
47 if ipv6 and gateways.ipv6 is not None:
48 subnet = Subnet.objects.get(id=gateways.ipv6.subnet_id)
49 if subnet.dns_servers:
50+ if not subnet.allow_dns:
51+ return subnet.dns_servers
52 rack_dns = []
53 for rack in {
54 self.get_boot_primary_rack_controller(),
55@@ -5009,18 +5013,9 @@ class Node(CleanSave, TimestampedModel):
56 if filtered_addresses:
57 routable_addrs_map[node] = filtered_addresses
58
59- # No default gateway subnet has specific DNS servers defined, so
60- # use MAAS for the default DNS server.
61 if gateways.ipv4 is None and gateways.ipv6 is None:
62- # If there are no default gateways, the default is the MAAS
63- # region IP address.
64- maas_dns_servers = get_dns_server_addresses(
65- rack_controller=self.get_boot_rack_controller(),
66- ipv4=ipv4,
67- ipv6=ipv6,
68- include_alternates=True,
69- default_region_ip=default_region_ip,
70- )
71+ # node with no gateway can only use routable addrs
72+ maas_dns_servers = []
73 routable_addrs_map = {
74 node: [
75 address
76diff --git a/src/maasserver/models/tests/test_node.py b/src/maasserver/models/tests/test_node.py
77index 33339a7..b6ac6a4 100644
78--- a/src/maasserver/models/tests/test_node.py
79+++ b/src/maasserver/models/tests/test_node.py
80@@ -8203,6 +8203,26 @@ class TestGetDefaultDNSServers(MAASServerTestCase):
81 node.get_default_dns_servers(), [ipv6_subnet_dns]
82 )
83
84+ def test_ignores_other_unroutable_rack_controllers_ipv4(self):
85+ # Regression test for LP:1896684
86+ rack_v4, rack_v6, node = self.make_Node_with_RackController(
87+ ipv4=True, ipv4_gateway=False, ipv6=False, ipv6_gateway=False
88+ )
89+ vlan = node.boot_interface.vlan
90+ rack = vlan.primary_rack
91+ rackif = rack.interface_set.first()
92+ rack_ips = [rack_v4]
93+ for _ in range(3):
94+ subnet = factory.make_Subnet(vlan=vlan, version=4)
95+ ip = factory.make_StaticIPAddress(subnet=subnet, interface=rackif)
96+ rack_ips.append(ip.ip)
97+ rack.save()
98+ resolve_hostname = self.patch(server_address, "resolve_hostname")
99+ resolve_hostname.side_effect = lambda hostname, version: set(
100+ map(IPAddress, rack_ips)
101+ )
102+ self.assertItemsEqual(node.get_default_dns_servers(), [rack_v4])
103+
104
105 class TestNode_Start(MAASTransactionServerTestCase):
106 """Tests for Node.start()."""
107diff --git a/src/maasserver/preseed_network.py b/src/maasserver/preseed_network.py
108index 8188603..395f3b3 100644
109--- a/src/maasserver/preseed_network.py
110+++ b/src/maasserver/preseed_network.py
111@@ -373,32 +373,37 @@ class InterfaceConfiguration:
112 if "addresses" not in v2_nameservers:
113 v2_nameservers["addresses"] = []
114
115- for ip in StaticIPAddress.objects.filter(
116- interface__node__in=[
117- subnet.vlan.primary_rack,
118- subnet.vlan.secondary_rack,
119- ],
120- subnet__vlan=subnet.vlan,
121- alloc_type__in=[
122- IPADDRESS_TYPE.AUTO,
123- IPADDRESS_TYPE.STICKY,
124- ],
125- ).exclude(ip=None):
126- if (
127- IPAddress(ip.get_ip()).version
128- == subnet.get_ip_version()
129- and ip.get_ip() not in v2_nameservers["addresses"]
130- ):
131+ if subnet.allow_dns:
132+ for ip in StaticIPAddress.objects.filter(
133+ interface__node__in=[
134+ subnet.vlan.primary_rack,
135+ subnet.vlan.secondary_rack,
136+ ],
137+ subnet__vlan=subnet.vlan,
138+ alloc_type__in=[
139+ IPADDRESS_TYPE.AUTO,
140+ IPADDRESS_TYPE.STICKY,
141+ ],
142+ ).exclude(ip=None):
143+ if ip.ip in v2_nameservers["addresses"]:
144+ continue
145+ ip_address = IPAddress(ip.ip)
146+ if ip_address.version != subnet.get_ip_version():
147+ continue
148+ if not subnet.gateway_ip:
149+ if ip_address not in subnet.get_ipnetwork():
150+ # without gateway, only use in-subnet addrs
151+ continue
152 v1_subnet_operation["dns_nameservers"].append(
153 ip.ip
154 )
155 v2_nameservers["addresses"].append(ip.ip)
156
157- if subnet.dns_servers:
158- v1_subnet_operation[
159- "dns_nameservers"
160- ] += subnet.dns_servers
161- v2_nameservers["addresses"] += subnet.dns_servers
162+ for ip in subnet.dns_servers:
163+ if ip in v2_nameservers["addresses"]:
164+ continue
165+ v1_subnet_operation["dns_nameservers"].append(ip)
166+ v2_nameservers["addresses"].append(ip)
167
168 if len(matching_subnet_routes) > 0 and version == 1:
169 # For the v1 YAML, the list of routes is rendered
170diff --git a/src/maasserver/tests/test_dhcp.py b/src/maasserver/tests/test_dhcp.py
171index d53f8bb..f445146 100644
172--- a/src/maasserver/tests/test_dhcp.py
173+++ b/src/maasserver/tests/test_dhcp.py
174@@ -1158,7 +1158,7 @@ class TestMakeSubnetConfig(MAASServerTestCase):
175 config = dhcp.make_subnet_config(
176 rack_controller,
177 subnet,
178- [factory.make_name("dns")],
179+ [factory.make_ipv4_address()],
180 [factory.make_name("ntp")],
181 default_domain,
182 search_list=default_domain.name,
183@@ -1457,7 +1457,7 @@ class TestMakeSubnetConfig(MAASServerTestCase):
184 config = dhcp.make_subnet_config(
185 rack_controller,
186 subnet,
187- [factory.make_name("dns")],
188+ [factory.make_ipv4_address()],
189 [factory.make_name("ntp")],
190 default_domain,
191 )
192@@ -1474,7 +1474,7 @@ class TestMakeSubnetConfig(MAASServerTestCase):
193 config = dhcp.make_subnet_config(
194 rack_controller,
195 subnet,
196- [factory.make_name("dns")],
197+ [factory.make_ipv4_address()],
198 [factory.make_name("ntp")],
199 default_domain,
200 )
201@@ -1495,7 +1495,7 @@ class TestMakeSubnetConfig(MAASServerTestCase):
202 config = dhcp.make_subnet_config(
203 rack_controller,
204 subnet,
205- [factory.make_name("dns")],
206+ [factory.make_ipv4_address()],
207 [factory.make_name("ntp")],
208 default_domain,
209 )
210@@ -1518,7 +1518,7 @@ class TestMakeSubnetConfig(MAASServerTestCase):
211 config = dhcp.make_subnet_config(
212 rack_controller,
213 subnet,
214- [factory.make_name("dns")],
215+ [factory.make_ipv4_address()],
216 [factory.make_name("ntp")],
217 default_domain,
218 search_list=search_list,
219@@ -1546,7 +1546,7 @@ class TestMakeSubnetConfig(MAASServerTestCase):
220 config = dhcp.make_subnet_config(
221 rack_controller,
222 subnet,
223- [factory.make_name("dns")],
224+ [factory.make_ipv6_address()],
225 [factory.make_name("ntp")],
226 default_domain,
227 search_list=search_list,
228@@ -1581,7 +1581,7 @@ class TestMakeSubnetConfig(MAASServerTestCase):
229 config = dhcp.make_subnet_config(
230 rack_controller,
231 subnet,
232- [factory.make_name("dns")],
233+ [factory.make_ipv4_address()],
234 [factory.make_name("ntp")],
235 default_domain,
236 )
237@@ -1609,7 +1609,7 @@ class TestMakeSubnetConfig(MAASServerTestCase):
238 config = dhcp.make_subnet_config(
239 rack_controller,
240 subnet,
241- [factory.make_name("dns")],
242+ [factory.make_ipv4_address()],
243 [factory.make_name("ntp")],
244 default_domain,
245 failover_peer=failover_peer,
246@@ -1643,7 +1643,7 @@ class TestMakeSubnetConfig(MAASServerTestCase):
247 config = dhcp.make_subnet_config(
248 rack_controller,
249 subnet,
250- [factory.make_name("dns")],
251+ [factory.make_ipv4_address()],
252 [factory.make_name("ntp")],
253 default_domain,
254 )
255@@ -1664,7 +1664,7 @@ class TestMakeSubnetConfig(MAASServerTestCase):
256 config = dhcp.make_subnet_config(
257 rack_controller,
258 subnet,
259- [factory.make_name("dns")],
260+ [factory.make_ipv4_address()],
261 [factory.make_name("ntp")],
262 default_domain,
263 subnets_dhcp_snippets=dhcp_snippets,
264@@ -1681,6 +1681,40 @@ class TestMakeSubnetConfig(MAASServerTestCase):
265 config["dhcp_snippets"],
266 )
267
268+ def test_subnet_without_gateway_restricts_nameservers(self):
269+ network1 = IPNetwork("10.9.8.0/24")
270+ network2 = IPNetwork("10.9.9.0/24")
271+ rackip1 = "10.9.8.1"
272+ rackip2 = "10.9.9.1"
273+ rack_controller = factory.make_RackController(interface=False)
274+ vlan = factory.make_VLAN()
275+ subnet1 = factory.make_Subnet(cidr=str(network1.cidr), vlan=vlan)
276+ subnet2 = factory.make_Subnet(
277+ cidr=str(network2.cidr), vlan=vlan, gateway_ip=None
278+ )
279+ factory.make_Interface(
280+ INTERFACE_TYPE.PHYSICAL, vlan=vlan, node=rack_controller
281+ )
282+ default_domain = Domain.objects.get_default_domain()
283+ config = dhcp.make_subnet_config(
284+ rack_controller,
285+ subnet1,
286+ [rackip1, rackip2],
287+ [factory.make_name("ntp")],
288+ default_domain,
289+ )
290+ self.assertIn(rackip1, config["dns_servers"])
291+ self.assertIn(rackip2, config["dns_servers"])
292+ config = dhcp.make_subnet_config(
293+ rack_controller,
294+ subnet2,
295+ [rackip1, rackip2],
296+ [factory.make_name("ntp")],
297+ default_domain,
298+ )
299+ self.assertNotIn(rackip1, config["dns_servers"])
300+ self.assertIn(rackip2, config["dns_servers"])
301+
302
303 class TestMakeHostsForSubnet(MAASServerTestCase):
304 def tests__returns_defined_hosts(self):
305diff --git a/src/maasserver/tests/test_preseed_network.py b/src/maasserver/tests/test_preseed_network.py
306index c19283a..279c203 100644
307--- a/src/maasserver/tests/test_preseed_network.py
308+++ b/src/maasserver/tests/test_preseed_network.py
309@@ -1761,6 +1761,55 @@ class TestNetplan(MAASServerTestCase):
310 v2["network"]["ethernets"][iface.name]["nameservers"],
311 )
312
313+ def test_allow_dns_false_does_not_include_rack_controllers(self):
314+ # Regression test for LP:1896684
315+ vlan = factory.make_VLAN()
316+ nameserver = "1.1.1.1"
317+ subnet = factory.make_Subnet(
318+ dns_servers=[nameserver], vlan=vlan, allow_dns=False
319+ )
320+ rack = factory.make_RackController(subnet=subnet)
321+ rack_iface = rack.interface_set.first()
322+ factory.make_StaticIPAddress(subnet=subnet, interface=rack_iface)
323+ vlan.primary_rack = rack
324+ vlan.save()
325+ node = factory.make_Node_with_Interface_on_Subnet(
326+ status=NODE_STATUS.DEPLOYING, subnet=subnet
327+ )
328+ iface = node.interface_set.first()
329+ factory.make_StaticIPAddress(subnet=subnet, interface=iface)
330+ v2 = self._render_netplan_dict(node)
331+ self.assertDictEqual(
332+ {"search": ["maas"], "addresses": [nameserver]},
333+ v2["network"]["ethernets"][iface.name]["nameservers"],
334+ )
335+
336+ def test_no_gateway_does_not_include_unroutable_controllers(self):
337+ # Regression test for LP:1896684
338+ vlan = factory.make_VLAN()
339+ subnet1 = factory.make_Subnet(
340+ dns_servers=[], vlan=vlan, version=4, gateway_ip=None
341+ )
342+ subnet2 = factory.make_Subnet(dns_servers=[], vlan=vlan, version=4)
343+ rack = factory.make_RackController(subnet=subnet1)
344+ rack_iface = rack.interface_set.first()
345+ rack_ip1 = factory.make_StaticIPAddress(
346+ subnet=subnet1, interface=rack_iface
347+ )
348+ factory.make_StaticIPAddress(subnet=subnet2, interface=rack_iface)
349+ vlan.primary_rack = rack
350+ vlan.save()
351+ node = factory.make_Node_with_Interface_on_Subnet(
352+ status=NODE_STATUS.DEPLOYING, subnet=subnet1
353+ )
354+ iface = node.interface_set.first()
355+ factory.make_StaticIPAddress(subnet=subnet1, interface=iface)
356+ v2 = self._render_netplan_dict(node)
357+ self.assertDictEqual(
358+ {"search": ["maas"], "addresses": [rack_ip1.ip]},
359+ v2["network"]["ethernets"][iface.name]["nameservers"],
360+ )
361+
362 def test_commissioning_dhcp_config(self):
363 # Verifies dhcp config is given when commissioning has run
364 # or just run and no AUTOIP has been acquired.

Subscribers

People subscribed via source and target branches