Merge ~ddstreet/maas:lp1896684-28 into maas:2.8

Proposed by Dan Streetman
Status: Merged
Approved by: Lee Trager
Approved revision: 843b1c54a4c01853dbdf7ae37929c92483d410fd
Merge reported by: MAAS Lander
Merged at revision: not available
Proposed branch: ~ddstreet/maas:lp1896684-28
Merge into: maas:2.8
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
Review via email: mp+392313@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-28 lp:~ddstreet/maas/+git/maas into -b 2.8 lp:~maas-committers/maas

STATUS: SUCCESS
COMMIT: 843b1c54a4c01853dbdf7ae37929c92483d410fd

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

UNABLE TO START LANDING

STATUS: MISSING COMMIT MESSAGE

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 7e867cd..1d371f4 100644
35--- a/src/maasserver/models/node.py
36+++ b/src/maasserver/models/node.py
37@@ -4905,6 +4905,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@@ -4931,6 +4933,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@@ -4977,18 +4981,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 3b9a6fb..6121686 100644
78--- a/src/maasserver/models/tests/test_node.py
79+++ b/src/maasserver/models/tests/test_node.py
80@@ -8132,6 +8132,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 779d1a6..99a3ce3 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 9c3a326..5fa1dd5 100644
307--- a/src/maasserver/tests/test_preseed_network.py
308+++ b/src/maasserver/tests/test_preseed_network.py
309@@ -1737,6 +1737,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