Merge ~cgrabowski/maas:fix_dns_update_race_condition into maas:master

Proposed by Christian Grabowski
Status: Merged
Approved by: Alexsander de Souza
Approved revision: a2e3f48b6d1b268f2bc9c4935df538227aa117d0
Merge reported by: MAAS Lander
Merged at revision: not available
Proposed branch: ~cgrabowski/maas:fix_dns_update_race_condition
Merge into: maas:master
Diff against target: 141 lines (+65/-5)
3 files modified
src/maasserver/region_controller.py (+13/-2)
src/maasserver/tests/test_region_controller.py (+52/-0)
src/provisioningserver/dns/zoneconfig.py (+0/-3)
Reviewer Review Type Date Requested Status
Alexsander de Souza Approve
MAAS Lander Approve
Review via email: mp+436566@code.launchpad.net

Commit message

store updates in a separate list while updating BIND

no longer remove BIND jnl

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

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

STATUS: SUCCESS
COMMIT: a2e3f48b6d1b268f2bc9c4935df538227aa117d0

review: Approve
Revision history for this message
Alexsander de Souza (alexsander-souza) wrote :

+1

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/src/maasserver/region_controller.py b/src/maasserver/region_controller.py
2index a7fa69c..a8cb828 100644
3--- a/src/maasserver/region_controller.py
4+++ b/src/maasserver/region_controller.py
5@@ -98,6 +98,8 @@ class RegionControllerService(Service):
6 self.needsProxyUpdate = False
7 self.needsRBACUpdate = False
8 self._dns_updates = []
9+ self._queued_updates = []
10+ self._dns_update_in_progress = False
11 self._dns_requires_full_reload = True
12 self.postgresListener = postgresListener
13 self.dnsResolver = Resolver(
14@@ -185,7 +187,10 @@ class RegionControllerService(Service):
15 self._dns_requires_full_reload = (
16 self._dns_requires_full_reload or need_reload
17 )
18- self._dns_updates += new_updates
19+ if self._dns_update_in_progress:
20+ self._queued_updates += new_updates
21+ else:
22+ self._dns_updates += new_updates
23
24 def startProcessing(self):
25 """Start the process looping call."""
26@@ -217,13 +222,19 @@ class RegionControllerService(Service):
27 return pause(delay)
28
29 def _clear_dynamic_dns_updates(d):
30- self._dns_updates = []
31+ if len(self._queued_updates) > 0:
32+ self._dns_updates = self._queued_updates
33+ self._queued_updates = []
34+ else:
35+ self._dns_updates = []
36 self._dns_requires_full_reload = False
37+ self._dns_update_in_progress = False
38 return d
39
40 defers = []
41 if self.needsDNSUpdate:
42 self.needsDNSUpdate = False
43+ self._dns_update_in_progress = True
44 d = deferToDatabase(
45 transactional(
46 dns_update_all_zones,
47diff --git a/src/maasserver/tests/test_region_controller.py b/src/maasserver/tests/test_region_controller.py
48index 4e97cdd..072d3b3 100644
49--- a/src/maasserver/tests/test_region_controller.py
50+++ b/src/maasserver/tests/test_region_controller.py
51@@ -36,6 +36,7 @@ from maastesting.matchers import (
52 MockCallsMatch,
53 MockNotCalled,
54 )
55+from provisioningserver.dns.config import DynamicDNSUpdate
56 from provisioningserver.utils.events import Event
57
58 wait_for_reactor = wait_for()
59@@ -841,3 +842,54 @@ class TestRegionControllerServiceTransactional(MAASTransactionServerTestCase):
60 self.assertEqual(rbac_sync.id, last_sync.id)
61 self.assertEqual(last_sync.resource_type, "resource-pool")
62 self.assertEqual(last_sync.sync_id, "x-y-z")
63+
64+ @wait_for_reactor
65+ @inlineCallbacks
66+ def test_queueDynamicDNSUpdate_queues_in_separate_list_while_update_in_progress(
67+ self,
68+ ):
69+ domain = yield deferToDatabase(factory.make_Domain)
70+ update_result = (random.randint(0, 10), True, [domain.name])
71+ record = yield deferToDatabase(factory.make_DNSResource, domain=domain)
72+ service = RegionControllerService(sentinel.listener)
73+
74+ update_zones = self.patch(region_controller, "dns_update_all_zones")
75+ update_zones.return_value = update_result
76+ check_serial = self.patch(service, "_checkSerial")
77+ check_serial.return_value = succeed(update_result)
78+
79+ service._dns_update_in_progress = True
80+ service.queueDynamicDNSUpdate(
81+ factory.make_name(),
82+ f"INSERT {domain.name} {record.name} A 30 10.10.10.10",
83+ )
84+ self.assertCountEqual(service._dns_updates, [])
85+ self.assertCountEqual(
86+ service._queued_updates,
87+ [
88+ DynamicDNSUpdate(
89+ operation="INSERT",
90+ name=f"{record.name}.{domain.name}",
91+ zone=domain.name,
92+ rectype="A",
93+ ttl=30,
94+ answer="10.10.10.10",
95+ )
96+ ],
97+ )
98+ service.needsDNSUpdate = True
99+ yield service.process()
100+ self.assertCountEqual(
101+ service._dns_updates,
102+ [
103+ DynamicDNSUpdate(
104+ operation="INSERT",
105+ name=f"{record.name}.{domain.name}",
106+ zone=domain.name,
107+ rectype="A",
108+ ttl=30,
109+ answer="10.10.10.10",
110+ )
111+ ],
112+ )
113+ self.assertCountEqual(service._queued_updates, [])
114diff --git a/src/provisioningserver/dns/zoneconfig.py b/src/provisioningserver/dns/zoneconfig.py
115index ec5da14..2992337 100644
116--- a/src/provisioningserver/dns/zoneconfig.py
117+++ b/src/provisioningserver/dns/zoneconfig.py
118@@ -7,7 +7,6 @@
119 from datetime import datetime
120 from itertools import chain
121 import os
122-from pathlib import Path
123
124 from netaddr import IPAddress, IPNetwork, spanning_cidr
125 from netaddr.core import AddrFormatError
126@@ -347,7 +346,6 @@ class DNSForwardZoneConfig(DomainConfigBase):
127 labels={"zone": self.domain},
128 )
129 else:
130- Path(f"{zi.target_path}.jnl").unlink(missing_ok=True)
131 self.requires_reload = True
132 needs_freeze_thaw = self.zone_file_exists(zi)
133 with freeze_thaw_zone(needs_freeze_thaw, zone=zi.zone_name):
134@@ -649,7 +647,6 @@ class DNSReverseZoneConfig(DomainConfigBase):
135 labels={"zone": self.domain},
136 )
137 else:
138- Path(f"{zi.target_path}.jnl").unlink(missing_ok=True)
139 self.requires_reload = True
140 needs_freeze_thaw = self.zone_file_exists(zi)
141 with freeze_thaw_zone(needs_freeze_thaw, zone=zi.zone_name):

Subscribers

People subscribed via source and target branches