Merge ~cgrabowski/maas:fix_dynamic_reverse_dns_update into maas:master

Proposed by Christian Grabowski
Status: Merged
Approved by: Christian Grabowski
Approved revision: 144270d806c5b144d2d6d5e3ab3a0a427031b73a
Merge reported by: MAAS Lander
Merged at revision: not available
Proposed branch: ~cgrabowski/maas:fix_dynamic_reverse_dns_update
Merge into: maas:master
Diff against target: 297 lines (+100/-8)
4 files modified
src/maasserver/dns/config.py (+24/-1)
src/maasserver/dns/tests/test_config.py (+64/-1)
src/maasserver/tests/test_region_controller.py (+4/-2)
src/provisioningserver/dns/config.py (+8/-4)
Reviewer Review Type Date Requested Status
MAAS Lander Approve
Alexsander de Souza Approve
Review via email: mp+448161@code.launchpad.net

Commit message

lookup subnet for reverse record zone generation

To post a comment you must log in.
Revision history for this message
Alexsander de Souza (alexsander-souza) wrote :

+1

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

UNIT TESTS
-b fix_dynamic_reverse_dns_update lp:~cgrabowski/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: FAILED
LOG: http://maas-ci.internal:8080/job/maas-tester/3212/console
COMMIT: 8d0875076551a1af4f1e1f86c2ab88022ab16854

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

UNIT TESTS
-b fix_dynamic_reverse_dns_update lp:~cgrabowski/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: FAILED
LOG: http://maas-ci.internal:8080/job/maas-tester/3214/console
COMMIT: 566455a3a2db4c6efc6daa906fce874433cc663b

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

UNIT TESTS
-b fix_dynamic_reverse_dns_update lp:~cgrabowski/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: SUCCESS
COMMIT: 144270d806c5b144d2d6d5e3ab3a0a427031b73a

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/src/maasserver/dns/config.py b/src/maasserver/dns/config.py
2index 91b1e72..2515a5a 100644
3--- a/src/maasserver/dns/config.py
4+++ b/src/maasserver/dns/config.py
5@@ -7,7 +7,7 @@
6 from collections import defaultdict
7
8 from django.conf import settings
9-from netaddr import IPAddress
10+from netaddr import IPAddress, IPNetwork
11
12 from maasserver.dns.zonegenerator import (
13 InternalDomain,
14@@ -32,6 +32,7 @@ from provisioningserver.dns.actions import (
15 bind_write_zones,
16 )
17 from provisioningserver.dns.config import DynamicDNSUpdate
18+from provisioningserver.dns.zoneconfig import DNSReverseZoneConfig
19 from provisioningserver.logger import get_maas_logger
20 from provisioningserver.prometheus.metrics import PROMETHEUS_METRICS
21 from provisioningserver.utils.shell import ExternalProcessError
22@@ -295,6 +296,16 @@ def get_internal_domain():
23 )
24
25
26+def get_reverse_zone_for_answer(answer):
27+ subnet = Subnet.objects.get_best_subnet_for_ip(answer)
28+ if not subnet:
29+ return None
30+
31+ network = IPNetwork(subnet.cidr)
32+ zone_info = DNSReverseZoneConfig.compose_zone_info(network)
33+ return zone_info[0].zone_name
34+
35+
36 def process_dns_update_notify(message):
37 updates = []
38 update_list = message.split(" ")
39@@ -321,12 +332,17 @@ def process_dns_update_notify(message):
40 ttl = int(update_list[-2]) if update_list[-2] else None
41 answer = update_list[-1]
42
43+ rev_zone = None
44+ if rectype in ("A", "AAAA") and answer is not None:
45+ rev_zone = get_reverse_zone_for_answer(answer)
46+
47 match op:
48 case "UPDATE":
49 updates.append(
50 DynamicDNSUpdate.create_from_trigger(
51 operation="DELETE",
52 zone=zone,
53+ rev_zone=rev_zone,
54 name=name,
55 rectype=rectype,
56 answer=answer,
57@@ -336,6 +352,7 @@ def process_dns_update_notify(message):
58 DynamicDNSUpdate.create_from_trigger(
59 operation="INSERT",
60 zone=zone,
61+ rev_zone=rev_zone,
62 name=name,
63 rectype=rectype,
64 ttl=ttl,
65@@ -347,6 +364,7 @@ def process_dns_update_notify(message):
66 DynamicDNSUpdate.create_from_trigger(
67 operation=op,
68 zone=zone,
69+ rev_zone=rev_zone,
70 name=name,
71 rectype=rectype,
72 ttl=ttl,
73@@ -361,6 +379,7 @@ def process_dns_update_notify(message):
74 DynamicDNSUpdate.create_from_trigger(
75 operation="DELETE",
76 zone=zone,
77+ rev_zone=rev_zone,
78 name=name,
79 rectype=rectype,
80 )
81@@ -370,6 +389,7 @@ def process_dns_update_notify(message):
82 DynamicDNSUpdate.create_from_trigger(
83 operation="DELETE",
84 zone=zone,
85+ rev_zone=rev_zone,
86 name=name,
87 rectype="AAAA",
88 )
89@@ -403,6 +423,7 @@ def process_dns_update_notify(message):
90 DynamicDNSUpdate.create_from_trigger(
91 operation="INSERT",
92 zone=zone,
93+ rev_zone=get_reverse_zone_for_answer(ip.ip),
94 name=name,
95 rectype=rectype,
96 ttl=ttl,
97@@ -415,6 +436,7 @@ def process_dns_update_notify(message):
98 DynamicDNSUpdate.create_from_trigger(
99 operation=op,
100 zone=zone,
101+ rev_zone=rev_zone,
102 name=name,
103 rectype=rectype,
104 answer=update_list[-1],
105@@ -425,6 +447,7 @@ def process_dns_update_notify(message):
106 DynamicDNSUpdate.create_from_trigger(
107 operation=op,
108 zone=zone,
109+ rev_zone=rev_zone,
110 name=name,
111 rectype=rectype,
112 )
113diff --git a/src/maasserver/dns/tests/test_config.py b/src/maasserver/dns/tests/test_config.py
114index 0a96814..dedeff2 100644
115--- a/src/maasserver/dns/tests/test_config.py
116+++ b/src/maasserver/dns/tests/test_config.py
117@@ -7,7 +7,7 @@ import time
118
119 from django.conf import settings
120 import dns.resolver
121-from netaddr import IPAddress
122+from netaddr import IPAddress, IPNetwork
123 from testtools.matchers import (
124 Contains,
125 Equals,
126@@ -26,6 +26,7 @@ from maasserver.dns.config import (
127 forward_domains_to_forwarded_zones,
128 get_internal_domain,
129 get_resource_name_for_subnet,
130+ get_reverse_zone_for_answer,
131 get_trusted_acls,
132 get_trusted_networks,
133 get_upstream_dns,
134@@ -797,6 +798,7 @@ class TestProcessDNSUpdateNotify(MAASServerTestCase):
135 DynamicDNSUpdate(
136 operation="INSERT",
137 zone=domain.name,
138+ rev_zone=get_reverse_zone_for_answer(ip),
139 name=f"{resource.name}.{domain.name}",
140 ttl=resource.address_ttl if resource.address_ttl else 60,
141 answer=ip,
142@@ -853,6 +855,7 @@ class TestProcessDNSUpdateNotify(MAASServerTestCase):
143 DynamicDNSUpdate(
144 operation="DELETE",
145 zone=domain.name,
146+ rev_zone=get_reverse_zone_for_answer(ip),
147 name=f"{resource.name}.{domain.name}",
148 answer=ip,
149 rectype="A" if IPAddress(ip).version == 4 else "AAAA",
150@@ -860,6 +863,7 @@ class TestProcessDNSUpdateNotify(MAASServerTestCase):
151 DynamicDNSUpdate(
152 operation="INSERT",
153 zone=domain.name,
154+ rev_zone=get_reverse_zone_for_answer(ip),
155 name=f"{resource.name}.{domain.name}",
156 ttl=resource.address_ttl if resource.address_ttl else 60,
157 answer=ip,
158@@ -898,6 +902,7 @@ class TestProcessDNSUpdateNotify(MAASServerTestCase):
159 DynamicDNSUpdate(
160 operation="INSERT",
161 zone=domain.name,
162+ rev_zone=get_reverse_zone_for_answer(ip2.ip),
163 name=f"{resource.name}.{domain.name}",
164 rectype="A" if IPAddress(ip2.ip).version == 4 else "AAAA",
165 answer=ip2.ip,
166@@ -932,6 +937,7 @@ class TestProcessDNSUpdateNotify(MAASServerTestCase):
167 DynamicDNSUpdate(
168 operation="INSERT",
169 zone=domain.name,
170+ rev_zone=get_reverse_zone_for_answer(ip2.ip),
171 name=f"{node.hostname}.{domain.name}",
172 rectype="A" if IPAddress(ip2.ip).version == 4 else "AAAA",
173 answer=ip2.ip,
174@@ -939,3 +945,60 @@ class TestProcessDNSUpdateNotify(MAASServerTestCase):
175 ],
176 result,
177 )
178+
179+ def test_insert_reverse_glue_zone(self):
180+ domain = factory.make_Domain()
181+ subnet = factory.make_Subnet(cidr="192.168.1.64/26")
182+ ip = subnet.get_next_ip_for_allocation()[0]
183+ resource = factory.make_DNSResource(domain=domain, ip=ip)
184+ message = f"INSERT {domain.name} {resource.name} A {resource.address_ttl if resource.address_ttl else 60} {ip}"
185+ zone = get_reverse_zone_for_answer(ip)
186+ result, _ = process_dns_update_notify(message)
187+ ip_split = ip.split(".")
188+ self.assertCountEqual(
189+ [
190+ DynamicDNSUpdate(
191+ operation="INSERT",
192+ zone=zone,
193+ name=".".join([ip_split[-1], zone]),
194+ ttl=resource.address_ttl if resource.address_ttl else 60,
195+ subnet=subnet.cidr,
196+ answer=f"{resource.name}.{domain.name}",
197+ rectype="PTR",
198+ )
199+ ],
200+ [
201+ DynamicDNSUpdate.as_reverse_record_update(
202+ res, IPNetwork(subnet.cidr)
203+ )
204+ for res in result
205+ ],
206+ )
207+
208+
209+class TestGetReverseZoneForUpdate(MAASServerTestCase):
210+ def test_get_reverse_zone_for_answer_v4_24(self):
211+ subnet = factory.make_Subnet(cidr="192.168.1.0/24")
212+ ip = subnet.get_next_ip_for_allocation()[0]
213+ rev_zone = get_reverse_zone_for_answer(ip)
214+ self.assertEqual("1.168.192.in-addr.arpa", rev_zone)
215+
216+ def test_get_reverse_zone_for_update_v4_26(self):
217+ subnet = factory.make_Subnet(cidr="192.168.1.0/26")
218+ ip = subnet.get_next_ip_for_allocation()[0]
219+ rev_zone = get_reverse_zone_for_answer(ip)
220+ self.assertEqual("0-26.1.168.192.in-addr.arpa", rev_zone)
221+
222+ def test_get_reverse_zone_for_update_v6_64(self):
223+ subnet = factory.make_Subnet(cidr="de:ad:be:ef:ca::/64")
224+ ip = subnet.get_next_ip_for_allocation()[0]
225+ rev_zone = get_reverse_zone_for_answer(ip)
226+ self.assertEqual("f.e.0.0.e.b.0.0.d.a.0.0.e.d.0.0.ip6.arpa", rev_zone)
227+
228+ def test_get_reverse_zone_for_update_v6_65(self):
229+ subnet = factory.make_Subnet(cidr="de:ad:be:ef:ca::/65")
230+ ip = subnet.get_next_ip_for_allocation()[0]
231+ rev_zone = get_reverse_zone_for_answer(ip)
232+ self.assertEqual(
233+ "0.f.e.0.0.e.b.0.0.d.a.0.0.e.d.0.0.ip6.arpa", rev_zone
234+ )
235diff --git a/src/maasserver/tests/test_region_controller.py b/src/maasserver/tests/test_region_controller.py
236index 1a9ee32..03c198f 100644
237--- a/src/maasserver/tests/test_region_controller.py
238+++ b/src/maasserver/tests/test_region_controller.py
239@@ -864,7 +864,8 @@ class TestRegionControllerServiceTransactional(MAASTransactionServerTestCase):
240 check_serial.return_value = succeed(update_result)
241
242 service._dns_update_in_progress = True
243- service.queueDynamicDNSUpdate(
244+ yield deferToDatabase(
245+ service.queueDynamicDNSUpdate,
246 factory.make_name(),
247 f"INSERT {domain.name} {record.name} A 30 10.10.10.10",
248 )
249@@ -913,7 +914,8 @@ class TestRegionControllerServiceTransactional(MAASTransactionServerTestCase):
250 check_serial.return_value = succeed(update_result)
251
252 service._dns_update_in_progress = True
253- service.queueDynamicDNSUpdate(
254+ yield deferToDatabase(
255+ service.queueDynamicDNSUpdate,
256 factory.make_name(),
257 f"INSERT {domain.name} {record.name} A 30 10.10.10.10",
258 )
259diff --git a/src/provisioningserver/dns/config.py b/src/provisioningserver/dns/config.py
260index de7aba1..264139e 100644
261--- a/src/provisioningserver/dns/config.py
262+++ b/src/provisioningserver/dns/config.py
263@@ -44,6 +44,7 @@ class DynamicDNSUpdate:
264 name: str
265 zone: str
266 rectype: str
267+ rev_zone: Optional[str] = None
268 ttl: Optional[int] = None
269 subnet: Optional[str] = None # for reverse updates
270 answer: Optional[str] = None
271@@ -72,19 +73,22 @@ class DynamicDNSUpdate:
272 return None
273 ip = IPAddress(fwd_update.answer)
274 name = ip.reverse_dns
275+ zone = fwd_update.rev_zone
276 if (ip.version == 4 and subnet.prefixlen > 24) or (
277 ip.version == 6 and subnet.prefixlen > 124
278 ):
279 name_split = ip.reverse_dns.split(".")
280- name_split = (
281- name_split[:1] + [f"0-{subnet.prefixlen}"] + name_split[1:]
282- )
283+ suffix = [zone]
284+ if not zone:
285+ suffix = [f"0-{subnet.prefixlen}"] + name_split[1:]
286+
287+ name_split = name_split[:1] + suffix
288 name = ".".join(name_split)
289
290 return cls(
291 operation=fwd_update.operation,
292 name=name,
293- zone=fwd_update.zone,
294+ zone=zone or fwd_update.zone,
295 subnet=str(subnet.cidr),
296 ttl=fwd_update.ttl,
297 answer=fwd_update.name,

Subscribers

People subscribed via source and target branches