Merge ~r00ta/maas:lp-2046255-fix-multiple-dns-A-records-for-host into maas:master
- Git
- lp:~r00ta/maas
- lp-2046255-fix-multiple-dns-A-records-for-host
- Merge into master
Status: | Merged |
---|---|
Approved by: | Jacopo Rota |
Approved revision: | 591c841f18c425307ac58aa0969a3a5bc96fab62 |
Merge reported by: | MAAS Lander |
Merged at revision: | not available |
Proposed branch: | ~r00ta/maas:lp-2046255-fix-multiple-dns-A-records-for-host |
Merge into: | maas:master |
Diff against target: |
1146 lines (+630/-79) 8 files modified
src/maasserver/region_controller.py (+25/-5) src/maasserver/tests/test_region_controller.py (+11/-6) src/maasserver/triggers/models/__init__.py (+0/-0) src/maasserver/triggers/models/dns_notifications.py (+51/-0) src/maasserver/triggers/models/tests/__init__.py (+0/-0) src/maasserver/triggers/models/tests/test_dns_notifications.py (+43/-0) src/maasserver/triggers/system.py (+271/-33) src/maasserver/triggers/tests/test_system.py (+229/-35) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
MAAS Lander | Approve | ||
Christian Grabowski | Approve | ||
Review via email: mp+457612@code.launchpad.net |
Commit message
fix: lp-2046255 IP addresses of non-boot interfaces should not add A records to <machine>.<domain>
Description of the change
non-boot interfaces should not add A records to <machine>.<domain>.
In addition to that, this MP makes every postgres notification unique because postgres drops duplicated notifications that are performed within the same transaction.
In our case when we perform operations on our entities (for example an interface), we execute multiple triggers within the same transaction and we must be sure that all the notifications are sent (the order is important).
- 12a3152... by Jacopo Rota
-
fix: lp-2046255 IP addresses of non-boot interfaces should not add A records to <machine>.<domain>
MAAS Lander (maas-lander) wrote : | # |
UNIT TESTS
-b lp-2046255-
STATUS: SUCCESS
COMMIT: 12a31525598d6d9
- 591c841... by Jacopo Rota
-
add missing __init__ to new module
MAAS Lander (maas-lander) wrote : | # |
UNIT TESTS
-b lp-2046255-
STATUS: SUCCESS
COMMIT: 591c841f18c4253
Preview Diff
1 | diff --git a/src/maasserver/region_controller.py b/src/maasserver/region_controller.py |
2 | index 756dfbd..7cc6428 100644 |
3 | --- a/src/maasserver/region_controller.py |
4 | +++ b/src/maasserver/region_controller.py |
5 | @@ -53,6 +53,9 @@ from maasserver.proxyconfig import proxy_update_config |
6 | from maasserver.rbac import RBACClient, Resource, SyncConflictError |
7 | from maasserver.secrets import SecretManager |
8 | from maasserver.service_monitor import service_monitor |
9 | +from maasserver.triggers.models.dns_notifications import ( |
10 | + DynamicDNSUpdateNotification, |
11 | +) |
12 | from maasserver.utils import synchronised |
13 | from maasserver.utils.orm import transactional, with_connection |
14 | from maasserver.utils.threads import deferToDatabase |
15 | @@ -181,12 +184,24 @@ class RegionControllerService(Service): |
16 | """ |
17 | Called when the `sys_dns_update` message is received |
18 | and queues updates for existing domains. |
19 | + Since an uncatched exception would stop the processing of the notifications, we catch and log |
20 | + every exception at top level. |
21 | + """ |
22 | + try: |
23 | + return self._queueDynamicDNSUpdate(channel, message) |
24 | + except Exception as e: |
25 | + log.warn( |
26 | + f"The message '{message}' might not have been processed correctly due to the exception: '{e}'" |
27 | + ) |
28 | + |
29 | + def _queueDynamicDNSUpdate(self, channel, message): |
30 | + """ |
31 | The updates are offloaded to the DatabaseTasksService in order to |
32 | process them in sequence and keep consuming the next postgres notifications. |
33 | """ |
34 | |
35 | - def updateCallback(data): |
36 | - (new_updates, need_reload) = data |
37 | + def updateCallback(result): |
38 | + (new_updates, need_reload) = result |
39 | self._dns_requires_full_reload = ( |
40 | self._dns_requires_full_reload or need_reload |
41 | ) |
42 | @@ -195,14 +210,19 @@ class RegionControllerService(Service): |
43 | else: |
44 | self._dns_updates += new_updates |
45 | |
46 | - log.debug("Start processing dynamic DNS update '{}'".format(message)) |
47 | - if message == "": |
48 | + log.debug(f"Start processing dynamic DNS update '{message}'") |
49 | + |
50 | + notification = DynamicDNSUpdateNotification(message) |
51 | + if not notification.is_valid(): |
52 | + log.warn( |
53 | + f"The dynamic dns update notification '{message}' is not valid. It will be dropped." |
54 | + ) |
55 | return |
56 | |
57 | self.dbtasks.deferTaskWithCallbacks( |
58 | process_dns_update_notify, |
59 | [updateCallback], |
60 | - message, |
61 | + notification.get_decoded_message(), |
62 | ) |
63 | |
64 | def startProcessing(self): |
65 | diff --git a/src/maasserver/tests/test_region_controller.py b/src/maasserver/tests/test_region_controller.py |
66 | index b688e58..0b45912 100644 |
67 | --- a/src/maasserver/tests/test_region_controller.py |
68 | +++ b/src/maasserver/tests/test_region_controller.py |
69 | @@ -866,7 +866,7 @@ class TestRegionControllerServiceTransactional(MAASTransactionServerTestCase): |
70 | service._dns_update_in_progress = True |
71 | service.queueDynamicDNSUpdate( |
72 | factory.make_name(), |
73 | - f"INSERT {domain.name} {record.name} A 30 10.10.10.10", |
74 | + f"b473ff04d60c0d2af08cb5c342d815f8 INSERT {domain.name} {record.name} A 30 10.10.10.10", |
75 | ) |
76 | |
77 | # Wait until all the dynamic updates are processed |
78 | @@ -921,7 +921,7 @@ class TestRegionControllerServiceTransactional(MAASTransactionServerTestCase): |
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 | + f"3108394140029edf0bdbffa68bb29556 INSERT {domain.name} {record.name} A 30 10.10.10.10", |
84 | ) |
85 | |
86 | # Wait until all the dynamic updates are processed |
87 | @@ -997,19 +997,24 @@ class TestRegionControllerServiceTransactional(MAASTransactionServerTestCase): |
88 | for _ in range(3): |
89 | service.queueDynamicDNSUpdate( |
90 | factory.make_name(), |
91 | - f"INSERT {domain.name} {record1.name} A 30 1.1.1.1", |
92 | + f"3108394140029edf0bdbffa68bb29556 INSERT {domain.name} {record1.name} A 30 1.1.1.1", |
93 | ) |
94 | service.queueDynamicDNSUpdate( |
95 | factory.make_name(), |
96 | - f"INSERT {domain.name} {record2.name} A 30 2.2.2.2", |
97 | + f"6fa241096ebabe34660c437fb0627b61 INSERT {domain.name} {record2.name} A 30 2.2.2.2", |
98 | ) |
99 | + # An invalid message that should be ignored |
100 | service.queueDynamicDNSUpdate( |
101 | factory.make_name(), |
102 | - f"DELETE {domain.name} {record1.name} A 30 1.1.1.1", |
103 | + f"INSERT {domain.name} {record2.name} A 30 10.2.2.2", |
104 | ) |
105 | service.queueDynamicDNSUpdate( |
106 | factory.make_name(), |
107 | - f"DELETE {domain.name} {record2.name} A 30 2.2.2.2", |
108 | + f"640f180ba9064411f30a3d5c587e86cc DELETE {domain.name} {record1.name} A 30 1.1.1.1", |
109 | + ) |
110 | + service.queueDynamicDNSUpdate( |
111 | + factory.make_name(), |
112 | + f"f53dcb0704c211e6f747b95b0ea3e128 DELETE {domain.name} {record2.name} A 30 2.2.2.2", |
113 | ) |
114 | |
115 | # Wait until all the dynamic updates are processed |
116 | diff --git a/src/maasserver/triggers/models/__init__.py b/src/maasserver/triggers/models/__init__.py |
117 | new file mode 100644 |
118 | index 0000000..e69de29 |
119 | --- /dev/null |
120 | +++ b/src/maasserver/triggers/models/__init__.py |
121 | diff --git a/src/maasserver/triggers/models/dns_notifications.py b/src/maasserver/triggers/models/dns_notifications.py |
122 | new file mode 100644 |
123 | index 0000000..46fcaff |
124 | --- /dev/null |
125 | +++ b/src/maasserver/triggers/models/dns_notifications.py |
126 | @@ -0,0 +1,51 @@ |
127 | +from re import compile |
128 | + |
129 | + |
130 | +class NotValidDNSNotificationPayload(Exception): |
131 | + """Error raised when the dynamic dns update notification is not valid.""" |
132 | + |
133 | + |
134 | +class DynamicDNSUpdateNotification: |
135 | + """ |
136 | + Postgres drops duplicated notifications fired in the same transaction. |
137 | + Since we are in this case for the dns notifications, we have to ensure that our notifications are unique. |
138 | + This is why the notification payload is in the format |
139 | + <random md5 string> <message> |
140 | + """ |
141 | + |
142 | + # Match MD5 string + white space. |
143 | + DYNAMIC_DNS_PREFIX_PATTERN = compile(r"^[0-9a-f]{32}\s*") |
144 | + |
145 | + def __init__(self, payload: str): |
146 | + self.payload = payload |
147 | + # cache the plain message the first time we parse it |
148 | + self.decoded_message = None |
149 | + |
150 | + def is_valid(self) -> bool: |
151 | + """ |
152 | + Checks if the payload is a valid dynamic dns update message. |
153 | + If it's valid, the result is cached. |
154 | + """ |
155 | + if self.decoded_message: |
156 | + return True |
157 | + |
158 | + match = self.DYNAMIC_DNS_PREFIX_PATTERN.match(self.payload) |
159 | + if not match: |
160 | + return False |
161 | + |
162 | + # Remove the prefix and cache the result |
163 | + self.decoded_message = self.payload[len(match.group(0)) :] |
164 | + return True |
165 | + |
166 | + def get_decoded_message(self) -> str: |
167 | + if self.decoded_message: |
168 | + return self.decoded_message |
169 | + |
170 | + # Check if it's valid and store the decoded message |
171 | + if not self.is_valid(): |
172 | + raise NotValidDNSNotificationPayload( |
173 | + "Message '%s' is not a valid dynamic dns update." |
174 | + % self.payload |
175 | + ) |
176 | + |
177 | + return self.decoded_message |
178 | diff --git a/src/maasserver/triggers/models/tests/__init__.py b/src/maasserver/triggers/models/tests/__init__.py |
179 | new file mode 100644 |
180 | index 0000000..e69de29 |
181 | --- /dev/null |
182 | +++ b/src/maasserver/triggers/models/tests/__init__.py |
183 | diff --git a/src/maasserver/triggers/models/tests/test_dns_notifications.py b/src/maasserver/triggers/models/tests/test_dns_notifications.py |
184 | new file mode 100644 |
185 | index 0000000..0119d40 |
186 | --- /dev/null |
187 | +++ b/src/maasserver/triggers/models/tests/test_dns_notifications.py |
188 | @@ -0,0 +1,43 @@ |
189 | +import pytest |
190 | + |
191 | +from maasserver.triggers.models.dns_notifications import ( |
192 | + DynamicDNSUpdateNotification, |
193 | + NotValidDNSNotificationPayload, |
194 | +) |
195 | +from maastesting.testcase import MAASTestCase |
196 | + |
197 | + |
198 | +class TestDynamicDNSUpdateNotification(MAASTestCase): |
199 | + def test_is_valid(self): |
200 | + valid_payloads = [ |
201 | + "5470596195891583856bdf849f2acfda RELOAD", |
202 | + "bedf5c93d7e7b82d45cfc555630cb8b1 INSERT maas taillow A 0 10.246.64.208", |
203 | + "adfbc39c6213a062afb584b90d508f52 DELETE mydomain mudkip A 192.168.33.163", |
204 | + ] |
205 | + for valid_payload in valid_payloads: |
206 | + notification = DynamicDNSUpdateNotification(valid_payload) |
207 | + assert notification.is_valid() |
208 | + |
209 | + def test_invalid_payloads(self): |
210 | + invalid_payloads = [ |
211 | + "", |
212 | + "5470596195891583849f2acfda RELOAD", |
213 | + "ADFBC39c6213a062afb584B90D508F52 DELETE mydomain mudkip A 192.168.33.163", |
214 | + ] |
215 | + for invalid_payload in invalid_payloads: |
216 | + notification = DynamicDNSUpdateNotification(invalid_payload) |
217 | + assert not notification.is_valid() |
218 | + |
219 | + def test_get_decoded_message(self): |
220 | + payload = "adfbc39c6213a062afb584b90d508f52 DELETE mydomain mudkip A 192.168.33.163" |
221 | + notification = DynamicDNSUpdateNotification(payload) |
222 | + assert ( |
223 | + notification.get_decoded_message() |
224 | + == "DELETE mydomain mudkip A 192.168.33.163" |
225 | + ) |
226 | + |
227 | + def test_get_decoded_message_if_invalid(self): |
228 | + payload = "" |
229 | + notification = DynamicDNSUpdateNotification(payload) |
230 | + with pytest.raises(NotValidDNSNotificationPayload): |
231 | + notification.get_decoded_message() |
232 | diff --git a/src/maasserver/triggers/system.py b/src/maasserver/triggers/system.py |
233 | index bfd514a..b8110c8 100644 |
234 | --- a/src/maasserver/triggers/system.py |
235 | +++ b/src/maasserver/triggers/system.py |
236 | @@ -285,6 +285,211 @@ CORE_REGIONRACKRPCONNECTION_DELETE = dedent( |
237 | """ |
238 | ) |
239 | |
240 | +CORE_GEN_RANDOM_PREFIX = dedent( |
241 | + """\ |
242 | + CREATE OR REPLACE FUNCTION gen_random_prefix() RETURNS TEXT AS $$ |
243 | + DECLARE |
244 | + result text; |
245 | + BEGIN |
246 | + result := md5(random()::text); |
247 | + RETURN result; |
248 | + END; |
249 | + $$ LANGUAGE plpgsql; |
250 | + """ |
251 | +) |
252 | + |
253 | +CORE_UPDATE_DATA_DNS_NOTIFICATION_FORMAT = dedent( |
254 | + """\ |
255 | + CREATE OR REPLACE FUNCTION update_data_dns_notification( |
256 | + id BIGINT |
257 | + ) RETURNS TEXT AS $$ |
258 | + DECLARE |
259 | + result text; |
260 | + BEGIN |
261 | + result := gen_random_prefix() || ' UPDATE-DATA ' || id; |
262 | + RETURN result; |
263 | + END; |
264 | + $$ LANGUAGE plpgsql; |
265 | + """ |
266 | +) |
267 | + |
268 | +CORE_INSERT_DATA_DNS_NOTIFICATION_FORMAT = dedent( |
269 | + """\ |
270 | + CREATE OR REPLACE FUNCTION insert_data_dns_notification( |
271 | + id BIGINT |
272 | + ) RETURNS TEXT AS $$ |
273 | + DECLARE |
274 | + result text; |
275 | + BEGIN |
276 | + result := gen_random_prefix() || ' INSERT-DATA ' || id; |
277 | + RETURN result; |
278 | + END; |
279 | + $$ LANGUAGE plpgsql; |
280 | + """ |
281 | +) |
282 | + |
283 | +CORE_DELETE_IP_DNS_NOTIFICATION_FORMAT = dedent( |
284 | + """\ |
285 | + CREATE OR REPLACE FUNCTION delete_ip_dns_notification( |
286 | + domain text, |
287 | + rname text, |
288 | + rtype text |
289 | + ) RETURNS TEXT AS $$ |
290 | + DECLARE |
291 | + result text; |
292 | + BEGIN |
293 | + result := gen_random_prefix() || ' DELETE-IP ' || domain || ' ' || rname || ' ' || rtype; |
294 | + RETURN result; |
295 | + END; |
296 | + $$ LANGUAGE plpgsql; |
297 | + """ |
298 | +) |
299 | + |
300 | +CORE_DELETE_IFACE_IP_DNS_NOTIFICATION_FORMAT = dedent( |
301 | + """\ |
302 | + CREATE OR REPLACE FUNCTION delete_iface_ip_dns_notification( |
303 | + domain text, |
304 | + current_hostname text, |
305 | + rtype text, |
306 | + interface_id text |
307 | + ) RETURNS TEXT AS $$ |
308 | + DECLARE |
309 | + result text; |
310 | + BEGIN |
311 | + result := gen_random_prefix() || ' DELETE-IFACE-IP ' || domain || ' ' || current_hostname || ' ' || rtype || ' ' || interface_id; |
312 | + RETURN result; |
313 | + END; |
314 | + $$ LANGUAGE plpgsql; |
315 | + """ |
316 | +) |
317 | + |
318 | +CORE_BOOT_INTERFACE_INSERT_DNS_NOTIFICATION_FORMAT = dedent( |
319 | + """\ |
320 | + CREATE OR REPLACE FUNCTION insert_boot_interface_dns_notification( |
321 | + domain text, |
322 | + current_hostname text, |
323 | + address_ttl INT, |
324 | + ip_address text |
325 | + ) RETURNS TEXT AS $$ |
326 | + DECLARE |
327 | + result text; |
328 | + BEGIN |
329 | + result := gen_random_prefix() || ' INSERT ' || domain || ' ' || current_hostname || ' A ' || address_ttl || ' ' || ip_address; |
330 | + RETURN result; |
331 | + END; |
332 | + $$ LANGUAGE plpgsql; |
333 | + """ |
334 | +) |
335 | + |
336 | +CORE_NON_BOOT_INTERFACE_INSERT_DNS_NOTIFICATION_FORMAT = dedent( |
337 | + """\ |
338 | + CREATE OR REPLACE FUNCTION insert_non_boot_interface_dns_notification( |
339 | + domain text, |
340 | + iface_name text, |
341 | + current_hostname text, |
342 | + address_ttl INT, |
343 | + ip_address text |
344 | + ) RETURNS TEXT AS $$ |
345 | + DECLARE |
346 | + result text; |
347 | + BEGIN |
348 | + result := gen_random_prefix() || ' INSERT ' || domain || ' ' || iface_name || '.' || current_hostname || ' A ' || address_ttl || ' ' || ip_address; |
349 | + RETURN result; |
350 | + END; |
351 | + $$ LANGUAGE plpgsql; |
352 | + """ |
353 | +) |
354 | + |
355 | +CORE_BOOT_INTERFACE_DELETE_DNS_NOTIFICATION_FORMAT = dedent( |
356 | + """\ |
357 | + CREATE OR REPLACE FUNCTION delete_boot_interface_dns_notification( |
358 | + domain text, |
359 | + current_hostname text, |
360 | + ip_address text |
361 | + ) RETURNS TEXT AS $$ |
362 | + DECLARE |
363 | + result text; |
364 | + BEGIN |
365 | + result := gen_random_prefix() || ' DELETE ' || domain || ' ' || current_hostname || ' A'; |
366 | + IF ip_address IS NOT NULL AND ip_address != '' THEN |
367 | + result := result || ' ' || ip_address; |
368 | + END IF; |
369 | + RETURN result; |
370 | + END; |
371 | + $$ LANGUAGE plpgsql; |
372 | + """ |
373 | +) |
374 | + |
375 | +CORE_DELETE_DNS_NOTIFICATION_FORMAT = dedent( |
376 | + """\ |
377 | + CREATE OR REPLACE FUNCTION delete_dns_notification( |
378 | + domain text, |
379 | + current_hostname text, |
380 | + rtype text |
381 | + ) RETURNS TEXT AS $$ |
382 | + DECLARE |
383 | + result text; |
384 | + BEGIN |
385 | + result := gen_random_prefix() || ' DELETE ' || domain || ' ' || current_hostname || ' ' || rtype; |
386 | + RETURN result; |
387 | + END; |
388 | + $$ LANGUAGE plpgsql; |
389 | + """ |
390 | +) |
391 | + |
392 | +CORE_NON_BOOT_INTERFACE_DELETE_DNS_NOTIFICATION_FORMAT = dedent( |
393 | + """\ |
394 | + CREATE OR REPLACE FUNCTION delete_non_boot_interface_dns_notification( |
395 | + domain text, |
396 | + iface_name text, |
397 | + current_hostname text, |
398 | + ip_address text |
399 | + ) RETURNS TEXT AS $$ |
400 | + DECLARE |
401 | + result text; |
402 | + BEGIN |
403 | + result := gen_random_prefix() || ' DELETE ' || domain || ' ' || iface_name || '.' || current_hostname || ' A'; |
404 | + IF ip_address IS NOT NULL AND ip_address != '' THEN |
405 | + result := result || ' ' || ip_address; |
406 | + END IF; |
407 | + RETURN result; |
408 | + END; |
409 | + $$ LANGUAGE plpgsql; |
410 | + """ |
411 | +) |
412 | + |
413 | +CORE_BOOT_INTERFACE_UPDATE_DNS_NOTIFICATION_FORMAT = dedent( |
414 | + """\ |
415 | + CREATE OR REPLACE FUNCTION update_boot_interface_dns_notification( |
416 | + domain text, |
417 | + current_hostname text, |
418 | + address_ttl INT, |
419 | + ip_address text |
420 | + ) RETURNS TEXT AS $$ |
421 | + DECLARE |
422 | + result text; |
423 | + BEGIN |
424 | + result := gen_random_prefix() || ' UPDATE ' || domain || ' ' || current_hostname || ' A ' || address_ttl || ' ' || ip_address; |
425 | + RETURN result; |
426 | + END; |
427 | + $$ LANGUAGE plpgsql; |
428 | + """ |
429 | +) |
430 | + |
431 | +CORE_RELOAD_DNS_NOTIFICATION_FORMAT = dedent( |
432 | + """\ |
433 | + CREATE OR REPLACE FUNCTION reload_dns_notification() |
434 | + RETURNS TEXT AS $$ |
435 | + DECLARE |
436 | + result text; |
437 | + BEGIN |
438 | + result := gen_random_prefix() || ' RELOAD'; |
439 | + RETURN result; |
440 | + END; |
441 | + $$ LANGUAGE plpgsql; |
442 | + """ |
443 | +) |
444 | + |
445 | # Triggered when the VLAN is modified. When DHCP is turned off/on it will alert |
446 | # the primary/secondary rack controller to update. If the primary rack or |
447 | # secondary rack is changed it will alert the previous and new rack controller. |
448 | @@ -1922,19 +2127,19 @@ def render_dns_dynamic_update_dnsresource_ip_addresses_procedure(op): |
449 | SELECT host(ip) INTO ip_addr FROM maasserver_staticipaddress WHERE id=NEW.staticipaddress_id; |
450 | SELECT name, domain_id, COALESCE(address_ttl, 0) INTO rname, rdomain_id, ttl FROM maasserver_dnsresource WHERE id=NEW.dnsresource_id; |
451 | SELECT name INTO domain FROM maasserver_domain WHERE id=rdomain_id; |
452 | - PERFORM pg_notify('sys_dns_updates', 'INSERT ' || domain || ' ' || rname || ' A ' || ttl || ' ' || ip_addr); |
453 | + PERFORM pg_notify('sys_dns_updates', insert_boot_interface_dns_notification(domain, rname, ttl, ip_addr)); |
454 | ELSIF (TG_OP = 'DELETE' AND TG_LEVEl = 'ROW') THEN |
455 | IF EXISTS(SELECT id FROM maasserver_dnsresource WHERE id=OLD.dnsresource_id) THEN |
456 | IF EXISTS(SELECT id FROM maasserver_staticipaddress WHERE id=OLD.staticipaddress_id) THEN |
457 | SELECT host(ip) INTO ip_addr FROM maasserver_staticipaddress WHERE id=OLD.staticipaddress_id; |
458 | SELECT name, domain_id INTO rname, rdomain_id FROM maasserver_dnsresource WHERE id=OLD.dnsresource_id; |
459 | SELECT name INTO domain FROM maasserver_domain WHERE id=rdomain_id; |
460 | - PERFORM pg_notify('sys_dns_updates', 'DELETE ' || domain || ' ' || rname || ' A ' || ip_addr); |
461 | + PERFORM pg_notify('sys_dns_updates', delete_boot_interface_dns_notification(domain, rname, ip_addr)); |
462 | ELSE |
463 | SELECT name, domain_id INTO rname, rdomain_id FROM maasserver_dnsresource WHERE id=NEW.dnsresource_id; |
464 | SELECT name INTO domain FROM maasserver_domain WHERE id=rdomain_id; |
465 | - PERFORM pg_notify('sys_dns_updates', 'DELETE-IP ' || domain || ' ' || rname || ' A'); |
466 | - PERFORM pg_notify('sys_dns_updates', 'DELETE-IP ' || domain || ' ' || rname || ' AAAA'); |
467 | + PERFORM pg_notify('sys_dns_updates', delete_ip_dns_notification(domain, rname, 'A')); |
468 | + PERFORM pg_notify('sys_dns_updates', delete_ip_dns_notification(domain, rname, 'AAAA')); |
469 | END IF; |
470 | END IF; |
471 | END IF; |
472 | @@ -1969,10 +2174,10 @@ def render_dns_dynamic_update_dnsresource_procedure(op): |
473 | FOREACH ip_addr IN ARRAY ips |
474 | LOOP |
475 | IF OLD.name <> NEW.name THEN |
476 | - PERFORM pg_notify('sys_dns_updates', 'DELETE ' || domain || ' ' || OLD.name || ' A ' || ip_addr); |
477 | - PERFORM pg_notify('sys_dns_updates', 'INSERT ' || domain || ' ' || NEW.name || ' A ' || NEW.address_ttl || ' ' || ip_addr); |
478 | + PERFORM pg_notify('sys_dns_updates', delete_boot_interface_dns_notification(domain, OLD.name, ip_addr)); |
479 | + PERFORM pg_notify('sys_dns_updates', insert_boot_interface_dns_notification(domain, NEW.name, NEW.address_ttl, ip_addr)); |
480 | ELSE |
481 | - PERFORM pg_notify('sys_dns_updates', 'UPDATE ' || domain || ' ' || NEW.name || ' A ' || NEW.address_ttl || ' ' || ip_addr); |
482 | + PERFORM pg_notify('sys_dns_updates', update_boot_interface_dns_notification(domain, NEW.name, NEW.address_ttl, ip_addr)); |
483 | END IF; |
484 | END LOOP; |
485 | END IF; |
486 | @@ -1981,7 +2186,7 @@ def render_dns_dynamic_update_dnsresource_procedure(op): |
487 | END IF; |
488 | ELSIF (TG_OP = 'DELETE' AND TG_LEVEL = 'ROW') THEN |
489 | SELECT name INTO domain FROM maasserver_domain WHERE id=NEW.domain_id; |
490 | - PERFORM pg_notify('sys_dns_updates', 'DELETE ' || domain || ' ' || OLD.name || ' A'); |
491 | + PERFORM pg_notify('sys_dns_updates', delete_boot_interface_dns_notification(domain, OLD.name, '')); |
492 | END IF; |
493 | RETURN NULL; |
494 | END; |
495 | @@ -2005,16 +2210,16 @@ def render_dns_dynamic_update_dnsdata_procedure(op): |
496 | ASSERT TG_LEVEL <> 'STATEMENT', 'Should not be used as a STATEMENT level trigger', TG_NAME; |
497 | IF (TG_OP = 'UPDATE' AND TG_LEVEL = 'ROW') THEN |
498 | IF NEW IS DISTINCT FROM OLD THEN |
499 | - PERFORM pg_notify('sys_dns_updates', 'UPDATE-DATA ' || NEW.id); |
500 | + PERFORM pg_notify('sys_dns_updates', update_data_dns_notification(NEW.id)); |
501 | ELSE |
502 | RETURN NULL; |
503 | END IF; |
504 | ELSIF (TG_OP = 'INSERT' AND TG_LEVEL = 'ROW') THEN |
505 | - PERFORM pg_notify('sys_dns_updates', 'INSERT-DATA ' || NEW.id); |
506 | + PERFORM pg_notify('sys_dns_updates', insert_data_dns_notification(NEW.id)); |
507 | ELSIF (TG_OP = 'DELETE' AND TG_LEVEL = 'ROW') THEN |
508 | SELECT name, domain_id INTO rname, rdomain_id from maasserver_dnsresource WHERE id=OLD.dnsresource_id; |
509 | SELECT name INTO domain FROM maasserver_domain WHERE id=rdomain_id; |
510 | - PERFORM pg_notify('sys_dns_updates', 'DELETE ' || domain || ' ' || rname || ' ' || OLD.rrtype); |
511 | + PERFORM pg_notify('sys_dns_updates', delete_dns_notification(domain, rname, OLD.rrtype)); |
512 | END IF; |
513 | RETURN NULL; |
514 | END; |
515 | @@ -2031,7 +2236,7 @@ def render_dns_dynamic_update_domain_procedure(op): |
516 | BEGIN |
517 | ASSERT TG_WHEN = 'AFTER', 'May only run as an AFTER trigger'; |
518 | ASSERT TG_LEVEL <> 'STATEMENT', 'Should not be used as a STATEMENT level trigger', TG_NAME; |
519 | - PERFORM pg_notify('sys_dns_updates', 'RELOAD'); |
520 | + PERFORM pg_notify('sys_dns_updates', reload_dns_notification()); |
521 | RETURN NULL; |
522 | END; |
523 | $$ LANGUAGE plpgsql; |
524 | @@ -2047,7 +2252,7 @@ def render_dns_dynamic_update_subnet_procedure(op): |
525 | BEGIN |
526 | ASSERT TG_WHEN = 'AFTER', 'May only run as an AFTER trigger'; |
527 | ASSERT TG_LEVEL <> 'STATEMENT', 'Should not be used as a STATEMENT level trigger', TG_NAME; |
528 | - PERFORM pg_notify('sys_dns_updates', 'RELOAD'); |
529 | + PERFORM pg_notify('sys_dns_updates', reload_dns_notification()); |
530 | RETURN NULL; |
531 | END; |
532 | $$ LANGUAGE plpgsql; |
533 | @@ -2095,9 +2300,9 @@ def render_dns_dynamic_update_interface_static_ip_address(op): |
534 | SELECT host(ip) INTO ip_addr FROM maasserver_staticipaddress WHERE id=NEW.staticipaddress_id; |
535 | IF (node_type={NODE_TYPE.MACHINE} OR node_type={NODE_TYPE.DEVICE}) THEN |
536 | IF (iface_id = boot_iface_id OR boot_iface_id is NULL) THEN |
537 | - PERFORM pg_notify('sys_dns_updates', 'INSERT ' || domain || ' ' || current_hostname || ' A ' || address_ttl || ' ' || ip_addr); |
538 | + PERFORM pg_notify('sys_dns_updates', insert_boot_interface_dns_notification(domain, current_hostname, address_ttl, ip_addr)); |
539 | ELSE |
540 | - PERFORM pg_notify('sys_dns_updates', 'INSERT ' || domain || ' ' || iface_name || '.' || current_hostname || ' A ' || address_ttl || ' ' || ip_addr); |
541 | + PERFORM pg_notify('sys_dns_updates', insert_non_boot_interface_dns_notification(domain, iface_name, current_hostname, address_ttl, ip_addr)); |
542 | END IF; |
543 | END IF; |
544 | ELSIF (TG_OP = 'DELETE' AND TG_LEVEL = 'ROW') THEN |
545 | @@ -2126,13 +2331,13 @@ def render_dns_dynamic_update_interface_static_ip_address(op): |
546 | IF EXISTS(SELECT id FROM maasserver_staticipaddress WHERE id=OLD.staticipaddress_id) THEN |
547 | SELECT host(ip) INTO ip_addr FROM maasserver_staticipaddress WHERE id=OLD.staticipaddress_id; |
548 | IF (iface_id = boot_iface_id) THEN |
549 | - PERFORM pg_notify('sys_dns_updates', 'DELETE ' || domain || ' ' || current_hostname || ' A ' || ip_addr); |
550 | + PERFORM pg_notify('sys_dns_updates', delete_boot_interface_dns_notification(domain, current_hostname, ip_addr)); |
551 | ELSE |
552 | - PERFORM pg_notify('sys_dns_updates', 'DELETE ' || domain || ' ' || iface_name || '.' || current_hostname || ' A ' || ip_addr); |
553 | + PERFORM pg_notify('sys_dns_updates', delete_non_boot_interface_dns_notification(domain, iface_name, current_hostname, ip_addr)); |
554 | END IF; |
555 | ELSE |
556 | - PERFORM pg_notify('sys_dns_updates', 'DELETE-IFACE-IP ' || domain || ' ' || current_hostname || ' A ' || OLD.interface_id); |
557 | - PERFORM pg_notify('sys_dns_updates', 'DELETE-IFACE-IP ' || domain || ' ' || current_hostname || ' AAAA ' || OLD.interface_id); |
558 | + PERFORM pg_notify('sys_dns_updates', delete_iface_ip_dns_notification(domain, current_hostname, 'A', OLD.interface_id)); |
559 | + PERFORM pg_notify('sys_dns_updates', delete_iface_ip_dns_notification(domain, current_hostname, 'AAAA', OLD.interface_id)); |
560 | END IF; |
561 | END IF; |
562 | END IF; |
563 | @@ -2154,20 +2359,41 @@ dns_dynamic_update_static_ip_address_update = dedent( |
564 | iface_name text; |
565 | address_ttl int; |
566 | current_interface_id bigint; |
567 | + iface_id bigint; |
568 | + boot_iface_id bigint; |
569 | BEGIN |
570 | IF NEW IS DISTINCT FROM OLD THEN |
571 | IF EXISTS(SELECT id FROM maasserver_interface_ip_addresses WHERE staticipaddress_id=NEW.id) THEN |
572 | SELECT interface_id INTO current_interface_id FROM maasserver_interface_ip_addresses WHERE staticipaddress_id=NEW.id; |
573 | - SELECT iface.name, node.hostname, domain_tbl.name, COALESCE(domain_tbl.ttl, 0) INTO iface_name, current_hostname, domain, address_ttl |
574 | - FROM maasserver_interface AS iface |
575 | + SELECT |
576 | + iface.name, |
577 | + node.hostname, |
578 | + domain_tbl.name, |
579 | + COALESCE(domain_tbl.ttl, 0), |
580 | + iface.id, |
581 | + node.boot_interface_id |
582 | + INTO |
583 | + iface_name, |
584 | + current_hostname, |
585 | + domain, |
586 | + address_ttl, |
587 | + iface_id, |
588 | + boot_iface_id |
589 | + FROM maasserver_interface AS iface |
590 | JOIN maasserver_node AS node ON iface.node_config_id = node.current_config_id |
591 | JOIN maasserver_domain AS domain_tbl ON domain_tbl.id=node.domain_id WHERE iface.id=current_interface_id; |
592 | IF OLD.ip IS NOT NULL THEN |
593 | - PERFORM pg_notify('sys_dns_updates', 'DELETE ' || domain || ' ' || current_hostname || ' A ' || host(OLD.ip)); |
594 | - PERFORM pg_notify('sys_dns_updates', 'DELETE ' || domain || ' ' || iface_name || '.' || current_hostname || ' A ' || host(OLD.ip)); |
595 | + IF (iface_id = boot_iface_id OR boot_iface_id is NULL) THEN |
596 | + PERFORM pg_notify('sys_dns_updates', delete_boot_interface_dns_notification(domain, current_hostname, host(OLD.ip))); |
597 | + ELSE |
598 | + PERFORM pg_notify('sys_dns_updates', delete_non_boot_interface_dns_notification(domain, iface_name, current_hostname, host(OLD.ip))); |
599 | + END IF; |
600 | + END IF; |
601 | + IF (iface_id = boot_iface_id OR boot_iface_id is NULL) THEN |
602 | + PERFORM pg_notify('sys_dns_updates', insert_boot_interface_dns_notification(domain, current_hostname, address_ttl, host(NEW.ip))); |
603 | + ELSE |
604 | + PERFORM pg_notify('sys_dns_updates', insert_non_boot_interface_dns_notification(domain, iface_name, current_hostname, address_ttl, host(NEW.ip))); |
605 | END IF; |
606 | - PERFORM pg_notify('sys_dns_updates', 'INSERT ' || domain || ' ' || current_hostname || ' A ' || address_ttl || ' ' || host(NEW.ip)); |
607 | - PERFORM pg_notify('sys_dns_updates', 'INSERT ' || domain || ' ' || iface_name || '.' || current_hostname || ' A ' || address_ttl || ' ' || host(NEW.ip)); |
608 | END IF; |
609 | END IF; |
610 | RETURN NULL; |
611 | @@ -2191,7 +2417,7 @@ def render_dns_dynamic_update_node(op): |
612 | new_ip text; |
613 | BEGIN |
614 | IF NEW.node_type <> {NODE_TYPE.DEVICE} AND NEW.node_type <> {NODE_TYPE.MACHINE} THEN |
615 | - PERFORM pg_notify('sys_dns_updates', 'RELOAD'); |
616 | + PERFORM pg_notify('sys_dns_updates', reload_dns_notification()); |
617 | ELSE |
618 | IF (TG_OP = 'UPDATE' AND TG_LEVEL = 'ROW') THEN |
619 | SELECT name, COALESCE(ttl, 0) INTO domain, address_ttl FROM maasserver_domain WHERE id=NEW.domain_id; |
620 | @@ -2201,21 +2427,21 @@ def render_dns_dynamic_update_node(op): |
621 | FROM maasserver_interface_ip_addresses AS link |
622 | JOIN maasserver_interface AS iface ON link.interface_id = iface.id |
623 | JOIN maasserver_staticipaddress AS ip_addr ON link.staticipaddress_id = ip_addr.id WHERE link.interface_id = OLD.boot_interface_id AND ip_addr.ip IS NOT NULL; |
624 | - PERFORM pg_notify('sys_dns_updates', 'DELETE ' || domain || ' ' || OLD.hostname || ' A ' || old_ip); |
625 | - PERFORM pg_notify('sys_dns_updates', 'INSERT ' || domain || ' ' || old_iface_name || '.' || NEW.hostname || ' A ' || address_ttl || ' ' || old_ip); |
626 | + PERFORM pg_notify('sys_dns_updates', delete_boot_interface_dns_notification(domain, OLD.hostname, old_ip)); |
627 | + PERFORM pg_notify('sys_dns_updates', insert_non_boot_interface_dns_notification(domain, old_iface_name, NEW.hostname, address_ttl, old_ip)); |
628 | END IF; |
629 | SELECT iface.name, host(ip_addr.ip) INTO iface_name, new_ip |
630 | FROM maasserver_interface_ip_addresses AS link |
631 | JOIN maasserver_interface AS iface ON link.interface_id = iface.id |
632 | JOIN maasserver_staticipaddress AS ip_addr on link.staticipaddress_id = ip_addr.id WHERE link.interface_id = NEW.boot_interface_id AND ip_addr.ip IS NOT NULL; |
633 | - PERFORM pg_notify('sys_dns_updates', 'DELETE ' || domain || ' ' || iface_name || '.' || OLD.hostname || ' A ' || new_ip); |
634 | - PERFORM pg_notify('sys_dns_updates', 'INSERT ' || domain || ' ' || NEW.hostname || ' A ' || address_ttl || ' ' || new_ip); |
635 | + PERFORM pg_notify('sys_dns_updates', delete_non_boot_interface_dns_notification(domain, iface_name, OLD.hostname, new_ip)); |
636 | + PERFORM pg_notify('sys_dns_updates', insert_boot_interface_dns_notification(domain, NEW.hostname, address_ttl, new_ip)); |
637 | ELSIF (OLD.hostname <> NEW.hostname) THEN |
638 | - PERFORM pg_notify('sys_dns_updates', 'RELOAD'); |
639 | + PERFORM pg_notify('sys_dns_updates', reload_dns_notification()); |
640 | END IF; |
641 | ELSE |
642 | SELECT name, COALESCE(ttl, 0) INTO domain, address_ttl FROM maasserver_domain WHERE id=OLD.domain_id; |
643 | - PERFORM pg_notify('sys_dns_updates', 'DELETE ' || domain || ' ' || OLD.hostname || ' A'); |
644 | + PERFORM pg_notify('sys_dns_updates', delete_boot_interface_dns_notification(domain, OLD.hostname, '')); |
645 | END IF; |
646 | END IF; |
647 | RETURN NULL; |
648 | @@ -2239,7 +2465,7 @@ dns_dynamic_update_interface_delete = dedent( |
649 | SELECT node_id INTO current_node_id FROM maasserver_nodeconfig WHERE id=OLD.node_config_id; |
650 | SELECT hostname, domain_id INTO current_hostname, current_domain_id FROM maasserver_node WHERE id=current_node_id; |
651 | SELECT name INTO domain FROM maasserver_domain WHERE id=current_domain_id; |
652 | - PERFORM pg_notify('sys_dns_updates', 'DELETE ' || domain || ' ' || OLD.name || '.' || current_hostname || ' A'); |
653 | + PERFORM pg_notify('sys_dns_updates', delete_non_boot_interface_dns_notification(domain, OLD.name, current_hostname, '')); |
654 | END IF; |
655 | RETURN NULL; |
656 | END; |
657 | @@ -2277,6 +2503,18 @@ def register_system_triggers(): |
658 | register_procedure(CORE_GET_NUMBER_OF_PROCESSES) |
659 | register_procedure(CORE_PICK_NEW_REGION) |
660 | register_procedure(CORE_SET_NEW_REGION) |
661 | + register_procedure(CORE_GEN_RANDOM_PREFIX) |
662 | + register_procedure(CORE_UPDATE_DATA_DNS_NOTIFICATION_FORMAT) |
663 | + register_procedure(CORE_INSERT_DATA_DNS_NOTIFICATION_FORMAT) |
664 | + register_procedure(CORE_DELETE_IP_DNS_NOTIFICATION_FORMAT) |
665 | + register_procedure(CORE_DELETE_IFACE_IP_DNS_NOTIFICATION_FORMAT) |
666 | + register_procedure(CORE_BOOT_INTERFACE_INSERT_DNS_NOTIFICATION_FORMAT) |
667 | + register_procedure(CORE_NON_BOOT_INTERFACE_INSERT_DNS_NOTIFICATION_FORMAT) |
668 | + register_procedure(CORE_BOOT_INTERFACE_DELETE_DNS_NOTIFICATION_FORMAT) |
669 | + register_procedure(CORE_DELETE_DNS_NOTIFICATION_FORMAT) |
670 | + register_procedure(CORE_NON_BOOT_INTERFACE_DELETE_DNS_NOTIFICATION_FORMAT) |
671 | + register_procedure(CORE_BOOT_INTERFACE_UPDATE_DNS_NOTIFICATION_FORMAT) |
672 | + register_procedure(CORE_RELOAD_DNS_NOTIFICATION_FORMAT) |
673 | |
674 | # RegionRackRPCConnection |
675 | register_procedure(CORE_REGIONRACKRPCONNECTION_INSERT) |
676 | diff --git a/src/maasserver/triggers/tests/test_system.py b/src/maasserver/triggers/tests/test_system.py |
677 | index 417bf6e..d236205 100644 |
678 | --- a/src/maasserver/triggers/tests/test_system.py |
679 | +++ b/src/maasserver/triggers/tests/test_system.py |
680 | @@ -15,6 +15,9 @@ from maasserver.testing.testcase import ( |
681 | MAASServerTestCase, |
682 | MAASTransactionServerTestCase, |
683 | ) |
684 | +from maasserver.triggers.models.dns_notifications import ( |
685 | + DynamicDNSUpdateNotification, |
686 | +) |
687 | from maasserver.triggers.system import register_system_triggers |
688 | from maasserver.triggers.testing import ( |
689 | NotifyHelperMixin, |
690 | @@ -132,8 +135,11 @@ class TestSysDNSUpdates( |
691 | "sys_dns_updates" |
692 | ) # ignore RELOAD from domain creation |
693 | msg = yield self.get_notify("sys_dns_updates") |
694 | + decoded_msg = DynamicDNSUpdateNotification( |
695 | + msg |
696 | + ).get_decoded_message() |
697 | self.assertEqual( |
698 | - msg, |
699 | + decoded_msg, |
700 | f"INSERT {domain.name} {rec.name} A {domain.ttl if domain.ttl else 0} {static_ip.ip}", |
701 | ) |
702 | finally: |
703 | @@ -162,8 +168,12 @@ class TestSysDNSUpdates( |
704 | try: |
705 | yield deferToDatabase(rec.delete) |
706 | msg = yield self.get_notify("sys_dns_updates") |
707 | + decoded_msg = DynamicDNSUpdateNotification( |
708 | + msg |
709 | + ).get_decoded_message() |
710 | self.assertEqual( |
711 | - msg, f"DELETE {domain.name} {rec.name} A {static_ip.ip}" |
712 | + decoded_msg, |
713 | + f"DELETE {domain.name} {rec.name} A {static_ip.ip}", |
714 | ) |
715 | finally: |
716 | self.stop_reading() |
717 | @@ -191,8 +201,12 @@ class TestSysDNSUpdates( |
718 | rec.address_ttl = 30 |
719 | yield deferToDatabase(rec.save) |
720 | msg = yield self.get_notify("sys_dns_updates") |
721 | + decoded_msg = DynamicDNSUpdateNotification( |
722 | + msg |
723 | + ).get_decoded_message() |
724 | self.assertEqual( |
725 | - msg, f"UPDATE {domain.name} {rec.name} A 30 {static_ip.ip}" |
726 | + decoded_msg, |
727 | + f"UPDATE {domain.name} {rec.name} A 30 {static_ip.ip}", |
728 | ) |
729 | finally: |
730 | self.stop_reading() |
731 | @@ -219,8 +233,12 @@ class TestSysDNSUpdates( |
732 | try: |
733 | yield deferToDatabase(rec.delete) |
734 | msg = yield self.get_notify("sys_dns_updates") |
735 | + decoded_msg = DynamicDNSUpdateNotification( |
736 | + msg |
737 | + ).get_decoded_message() |
738 | self.assertEqual( |
739 | - msg, f"DELETE {domain.name} {rec.name} A {static_ip.ip}" |
740 | + decoded_msg, |
741 | + f"DELETE {domain.name} {rec.name} A {static_ip.ip}", |
742 | ) |
743 | finally: |
744 | self.stop_reading() |
745 | @@ -254,8 +272,11 @@ class TestSysDNSUpdates( |
746 | dnsdata.rrdata = factory.make_name() |
747 | yield deferToDatabase(dnsdata.save) |
748 | msg = yield self.get_notify("sys_dns_updates") |
749 | + decoded_msg = DynamicDNSUpdateNotification( |
750 | + msg |
751 | + ).get_decoded_message() |
752 | self.assertEqual( |
753 | - msg, |
754 | + decoded_msg, |
755 | f"UPDATE-DATA {dnsdata.id}", |
756 | ) |
757 | finally: |
758 | @@ -288,8 +309,11 @@ class TestSysDNSUpdates( |
759 | }, |
760 | ) |
761 | msg = yield self.get_notify("sys_dns_updates") |
762 | + decoded_msg = DynamicDNSUpdateNotification( |
763 | + msg |
764 | + ).get_decoded_message() |
765 | self.assertEqual( |
766 | - msg, |
767 | + decoded_msg, |
768 | f"INSERT-DATA {dnsdata.id}", |
769 | ) |
770 | finally: |
771 | @@ -323,8 +347,12 @@ class TestSysDNSUpdates( |
772 | try: |
773 | yield deferToDatabase(dnsdata.delete) |
774 | msg = yield self.get_notify("sys_dns_updates") |
775 | + decoded_msg = DynamicDNSUpdateNotification( |
776 | + msg |
777 | + ).get_decoded_message() |
778 | self.assertEqual( |
779 | - msg, f"DELETE {domain.name} {rec.name} {dnsdata.rrtype}" |
780 | + decoded_msg, |
781 | + f"DELETE {domain.name} {rec.name} {dnsdata.rrtype}", |
782 | ) |
783 | finally: |
784 | self.stop_reading() |
785 | @@ -345,7 +373,10 @@ class TestSysDNSUpdates( |
786 | try: |
787 | yield deferToDatabase(self.create_domain) |
788 | msg = yield self.get_notify("sys_dns_updates") |
789 | - self.assertEqual(msg, "RELOAD") |
790 | + decoded_msg = DynamicDNSUpdateNotification( |
791 | + msg |
792 | + ).get_decoded_message() |
793 | + self.assertEqual(decoded_msg, "RELOAD") |
794 | finally: |
795 | self.stop_reading() |
796 | yield self.postgres_listener_service.stopService() |
797 | @@ -365,7 +396,10 @@ class TestSysDNSUpdates( |
798 | try: |
799 | yield deferToDatabase(self.create_subnet) |
800 | msg = yield self.get_notify("sys_dns_updates") |
801 | - self.assertEqual(msg, "RELOAD") |
802 | + decoded_msg = DynamicDNSUpdateNotification( |
803 | + msg |
804 | + ).get_decoded_message() |
805 | + self.assertEqual(decoded_msg, "RELOAD") |
806 | finally: |
807 | self.stop_reading() |
808 | yield self.postgres_listener_service.stopService() |
809 | @@ -415,8 +449,11 @@ class TestSysDNSUpdates( |
810 | ) |
811 | ) |
812 | msg1 = yield self.get_notify("sys_dns_updates") |
813 | + decoded_msg1 = DynamicDNSUpdateNotification( |
814 | + msg1 |
815 | + ).get_decoded_message() |
816 | self.assertEqual( |
817 | - msg1, |
818 | + decoded_msg1, |
819 | f"INSERT {domain.name} {node.hostname} A 0 {expected_ip.ip}", |
820 | ) |
821 | finally: |
822 | @@ -471,8 +508,11 @@ class TestSysDNSUpdates( |
823 | ) |
824 | ) |
825 | msg1 = yield self.get_notify("sys_dns_updates") |
826 | + decoded_msg1 = DynamicDNSUpdateNotification( |
827 | + msg1 |
828 | + ).get_decoded_message() |
829 | self.assertEqual( |
830 | - msg1, |
831 | + decoded_msg1, |
832 | f"INSERT {domain.name} {node.hostname} A 0 {expected_ip.ip}", |
833 | ) |
834 | finally: |
835 | @@ -516,8 +556,12 @@ class TestSysDNSUpdates( |
836 | try: |
837 | yield deferToDatabase(iface.unlink_ip_address, ip1) |
838 | msg1 = yield self.get_notify("sys_dns_updates") |
839 | + decoded_msg1 = DynamicDNSUpdateNotification( |
840 | + msg1 |
841 | + ).get_decoded_message() |
842 | self.assertEqual( |
843 | - msg1, f"DELETE {domain.name} {node.hostname} A {ip1.ip}" |
844 | + decoded_msg1, |
845 | + f"DELETE {domain.name} {node.hostname} A {ip1.ip}", |
846 | ) |
847 | finally: |
848 | self.stop_reading() |
849 | @@ -590,14 +634,17 @@ class TestSysDNSUpdates( |
850 | ) |
851 | for exp in expected_msgs: |
852 | msg = yield self.get_notify("sys_dns_updates") |
853 | - self.assertEqual(msg, exp) |
854 | + decoded_msg = DynamicDNSUpdateNotification( |
855 | + msg |
856 | + ).get_decoded_message() |
857 | + self.assertEqual(decoded_msg, exp) |
858 | finally: |
859 | self.stop_reading() |
860 | yield self.postgres_listener_service.stopService() |
861 | |
862 | @wait_for_reactor |
863 | @inlineCallbacks |
864 | - def test_dns_dynamc_update_ip_update(self): |
865 | + def test_dns_dynamc_update_ip_boot_interface_update(self): |
866 | listener = self.make_listener_without_delay() |
867 | yield self.set_service(listener) |
868 | yield deferToDatabase( |
869 | @@ -638,22 +685,87 @@ class TestSysDNSUpdates( |
870 | try: |
871 | yield deferToDatabase(_set_new_ip) |
872 | msg1 = yield self.get_notify("sys_dns_updates") |
873 | + decoded_msg1 = DynamicDNSUpdateNotification( |
874 | + msg1 |
875 | + ).get_decoded_message() |
876 | self.assertEqual( |
877 | - msg1, f"DELETE {domain.name} {node.hostname} A {old_ip}" |
878 | + decoded_msg1, |
879 | + f"DELETE {domain.name} {node.hostname} A {old_ip}", |
880 | ) |
881 | msg2 = yield self.get_notify("sys_dns_updates") |
882 | + decoded_msg2 = DynamicDNSUpdateNotification( |
883 | + msg2 |
884 | + ).get_decoded_message() |
885 | self.assertEqual( |
886 | - msg2, |
887 | - f"DELETE {domain.name} {iface.name}.{node.hostname} A {old_ip}", |
888 | + decoded_msg2, |
889 | + f"INSERT {domain.name} {node.hostname} A 0 {ip.ip}", |
890 | ) |
891 | - msg3 = yield self.get_notify("sys_dns_updates") |
892 | + finally: |
893 | + self.stop_reading() |
894 | + yield self.postgres_listener_service.stopService() |
895 | + |
896 | + @wait_for_reactor |
897 | + @inlineCallbacks |
898 | + def test_dns_dynamc_update_ip_non_boot_interface_update(self): |
899 | + listener = self.make_listener_without_delay() |
900 | + yield self.set_service(listener) |
901 | + yield deferToDatabase( |
902 | + self.register_trigger, |
903 | + "maasserver_staticipaddress", |
904 | + "sys_dns_updates", |
905 | + ops=("update",), |
906 | + trigger="sys_dns_updates_ip_update", |
907 | + ) |
908 | + vlan = yield deferToDatabase(self.create_vlan) |
909 | + subnet = yield deferToDatabase( |
910 | + self.create_subnet, params={"vlan": vlan} |
911 | + ) |
912 | + node = yield deferToDatabase( |
913 | + self.create_node_with_interface, |
914 | + params={"subnet": subnet, "status": NODE_STATUS.DEPLOYED}, |
915 | + ) |
916 | + domain = yield deferToDatabase(Domain.objects.get_default_domain) |
917 | + # set boot interface |
918 | + yield deferToDatabase( |
919 | + lambda: node.current_config.interface_set.first() |
920 | + ) |
921 | + iface2 = yield deferToDatabase( |
922 | + self.create_interface, params={"node": node} |
923 | + ) |
924 | + # Change ip of the non-boot interface |
925 | + ip = yield deferToDatabase( |
926 | + lambda: self.create_staticipaddress( |
927 | + params={ |
928 | + "ip": subnet.get_next_ip_for_allocation()[0], |
929 | + "interface": iface2, |
930 | + "subnet": subnet, |
931 | + } |
932 | + ) |
933 | + ) |
934 | + old_ip = ip.ip |
935 | + |
936 | + def _set_new_ip(): |
937 | + ip.ip = subnet.get_next_ip_for_allocation()[0] |
938 | + ip.save() |
939 | + |
940 | + self.start_reading() |
941 | + try: |
942 | + yield deferToDatabase(_set_new_ip) |
943 | + msg1 = yield self.get_notify("sys_dns_updates") |
944 | + decoded_msg1 = DynamicDNSUpdateNotification( |
945 | + msg1 |
946 | + ).get_decoded_message() |
947 | self.assertEqual( |
948 | - msg3, f"INSERT {domain.name} {node.hostname} A 0 {ip.ip}" |
949 | + decoded_msg1, |
950 | + f"DELETE {domain.name} {iface2.name}.{node.hostname} A {old_ip}", |
951 | ) |
952 | - msg4 = yield self.get_notify("sys_dns_updates") |
953 | + msg2 = yield self.get_notify("sys_dns_updates") |
954 | + decoded_msg2 = DynamicDNSUpdateNotification( |
955 | + msg2 |
956 | + ).get_decoded_message() |
957 | self.assertEqual( |
958 | - msg4, |
959 | - f"INSERT {domain.name} {iface.name}.{node.hostname} A 0 {ip.ip}", |
960 | + decoded_msg2, |
961 | + f"INSERT {domain.name} {iface2.name}.{node.hostname} A 0 {ip.ip}", |
962 | ) |
963 | finally: |
964 | self.stop_reading() |
965 | @@ -674,7 +786,10 @@ class TestSysDNSUpdates( |
966 | try: |
967 | yield deferToDatabase(self.create_rack_controller) |
968 | msg = yield self.get_notify("sys_dns_updates") |
969 | - self.assertEqual(msg, "RELOAD") |
970 | + decoded_msg = DynamicDNSUpdateNotification( |
971 | + msg |
972 | + ).get_decoded_message() |
973 | + self.assertEqual(decoded_msg, "RELOAD") |
974 | finally: |
975 | self.stop_reading() |
976 | yield self.postgres_listener_service.stopService() |
977 | @@ -696,7 +811,10 @@ class TestSysDNSUpdates( |
978 | controller.cpu_speed = 10 |
979 | yield deferToDatabase(controller.save) |
980 | msg = yield self.get_notify("sys_dns_updates") |
981 | - self.assertEqual(msg, "RELOAD") |
982 | + decoded_msg = DynamicDNSUpdateNotification( |
983 | + msg |
984 | + ).get_decoded_message() |
985 | + self.assertEqual(decoded_msg, "RELOAD") |
986 | finally: |
987 | self.stop_reading() |
988 | yield self.postgres_listener_service.stopService() |
989 | @@ -718,14 +836,19 @@ class TestSysDNSUpdates( |
990 | try: |
991 | yield deferToDatabase(node.delete) |
992 | msg = yield self.get_notify("sys_dns_updates") |
993 | - self.assertEqual(msg, f"DELETE {domain.name} {node.hostname} A") |
994 | + decoded_msg = DynamicDNSUpdateNotification( |
995 | + msg |
996 | + ).get_decoded_message() |
997 | + self.assertEqual( |
998 | + decoded_msg, f"DELETE {domain.name} {node.hostname} A" |
999 | + ) |
1000 | finally: |
1001 | self.stop_reading() |
1002 | yield self.postgres_listener_service.stopService() |
1003 | |
1004 | @wait_for_reactor |
1005 | @inlineCallbacks |
1006 | - def test_dns_dynamic_update_interface_delete(self): |
1007 | + def test_dns_dynamic_update_boot_interface_delete(self): |
1008 | listener = self.make_listener_without_delay() |
1009 | yield self.set_service(listener) |
1010 | yield deferToDatabase( |
1011 | @@ -745,9 +868,57 @@ class TestSysDNSUpdates( |
1012 | self.start_reading() |
1013 | try: |
1014 | yield deferToDatabase(iface.delete) |
1015 | - msg = yield self.get_notify("sys_dns_updates") |
1016 | + msg1 = yield self.get_notify("sys_dns_updates") |
1017 | + decoded_msg = DynamicDNSUpdateNotification( |
1018 | + msg1 |
1019 | + ).get_decoded_message() |
1020 | + self.assertEqual( |
1021 | + decoded_msg, f"DELETE {domain.name} {node.hostname} A" |
1022 | + ) |
1023 | + msg2 = yield self.get_notify("sys_dns_updates") |
1024 | + decoded_msg2 = DynamicDNSUpdateNotification( |
1025 | + msg2 |
1026 | + ).get_decoded_message() |
1027 | + self.assertEqual( |
1028 | + decoded_msg2, |
1029 | + f"DELETE {domain.name} {iface.name}.{node.hostname} A", |
1030 | + ) |
1031 | + finally: |
1032 | + self.stop_reading() |
1033 | + yield self.postgres_listener_service.stopService() |
1034 | + |
1035 | + @wait_for_reactor |
1036 | + @inlineCallbacks |
1037 | + def test_dns_dynamic_update_non_boot_interface_delete(self): |
1038 | + listener = self.make_listener_without_delay() |
1039 | + yield self.set_service(listener) |
1040 | + yield deferToDatabase( |
1041 | + self.register_trigger, |
1042 | + "maasserver_node", |
1043 | + "sys_dns_updates", |
1044 | + ops=("delete",), |
1045 | + ) |
1046 | + subnet = yield deferToDatabase(self.create_subnet) |
1047 | + node = yield deferToDatabase( |
1048 | + self.create_node_with_interface, params={"subnet": subnet} |
1049 | + ) |
1050 | + domain = yield deferToDatabase(Domain.objects.get_default_domain) |
1051 | + yield deferToDatabase( |
1052 | + lambda: node.current_config.interface_set.first() |
1053 | + ) |
1054 | + iface2 = yield deferToDatabase( |
1055 | + self.create_interface, params={"node": node} |
1056 | + ) |
1057 | + self.start_reading() |
1058 | + try: |
1059 | + yield deferToDatabase(iface2.delete) |
1060 | + msg1 = yield self.get_notify("sys_dns_updates") |
1061 | + decoded_msg = DynamicDNSUpdateNotification( |
1062 | + msg1 |
1063 | + ).get_decoded_message() |
1064 | self.assertEqual( |
1065 | - msg, f"DELETE {domain.name} {iface.name}.{node.hostname} A" |
1066 | + decoded_msg, |
1067 | + f"DELETE {domain.name} {iface2.name}.{node.hostname} A", |
1068 | ) |
1069 | finally: |
1070 | self.stop_reading() |
1071 | @@ -812,12 +983,19 @@ class TestSysDNSUpdates( |
1072 | ) |
1073 | ) |
1074 | msg1 = yield self.get_notify("sys_dns_updates") |
1075 | + decoded_msg1 = DynamicDNSUpdateNotification( |
1076 | + msg1 |
1077 | + ).get_decoded_message() |
1078 | self.assertEqual( |
1079 | - msg1, f"INSERT {domain.name} {node.hostname} A 0 {ip1.ip}" |
1080 | + decoded_msg1, |
1081 | + f"INSERT {domain.name} {node.hostname} A 0 {ip1.ip}", |
1082 | ) |
1083 | msg2 = yield self.get_notify("sys_dns_updates") |
1084 | + decoded_msg2 = DynamicDNSUpdateNotification( |
1085 | + msg2 |
1086 | + ).get_decoded_message() |
1087 | self.assertEqual( |
1088 | - msg2, |
1089 | + decoded_msg2, |
1090 | f"INSERT {domain.name} {iface2.name}.{node.hostname} A 0 {ip2.ip}", |
1091 | ) |
1092 | finally: |
1093 | @@ -873,8 +1051,12 @@ class TestSysDNSUpdates( |
1094 | ) |
1095 | ) |
1096 | msg1 = yield self.get_notify("sys_dns_updates") |
1097 | + decoded_msg1 = DynamicDNSUpdateNotification( |
1098 | + msg1 |
1099 | + ).get_decoded_message() |
1100 | self.assertEqual( |
1101 | - msg1, f"INSERT {domain.name} {node.hostname} A 0 {ip1.ip}" |
1102 | + decoded_msg1, |
1103 | + f"INSERT {domain.name} {node.hostname} A 0 {ip1.ip}", |
1104 | ) |
1105 | finally: |
1106 | self.stop_reading() |
1107 | @@ -943,23 +1125,35 @@ class TestSysDNSUpdates( |
1108 | node.boot_interface = iface2 |
1109 | yield deferToDatabase(node.save) |
1110 | msg1 = yield self.get_notify("sys_dns_updates") |
1111 | + decoded_msg1 = DynamicDNSUpdateNotification( |
1112 | + msg1 |
1113 | + ).get_decoded_message() |
1114 | self.assertEqual( |
1115 | - msg1, |
1116 | + decoded_msg1, |
1117 | f"DELETE {domain.name} {node.hostname} A {ip1.ip}", |
1118 | ) |
1119 | msg2 = yield self.get_notify("sys_dns_updates") |
1120 | + decoded_msg2 = DynamicDNSUpdateNotification( |
1121 | + msg2 |
1122 | + ).get_decoded_message() |
1123 | self.assertEqual( |
1124 | - msg2, |
1125 | + decoded_msg2, |
1126 | f"INSERT {domain.name} {iface1.name}.{node.hostname} A 0 {ip1.ip}", |
1127 | ) |
1128 | msg3 = yield self.get_notify("sys_dns_updates") |
1129 | + decoded_msg3 = DynamicDNSUpdateNotification( |
1130 | + msg3 |
1131 | + ).get_decoded_message() |
1132 | self.assertEqual( |
1133 | - msg3, |
1134 | + decoded_msg3, |
1135 | f"DELETE {domain.name} {iface2.name}.{node.hostname} A {ip2.ip}", |
1136 | ) |
1137 | msg4 = yield self.get_notify("sys_dns_updates") |
1138 | + decoded_msg4 = DynamicDNSUpdateNotification( |
1139 | + msg4 |
1140 | + ).get_decoded_message() |
1141 | self.assertEqual( |
1142 | - msg4, |
1143 | + decoded_msg4, |
1144 | f"INSERT {domain.name} {node.hostname} A 0 {ip2.ip}", |
1145 | ) |
1146 | finally: |
UNIT TESTS fix-multiple- dns-A-records- for-host lp:~r00ta/maas/+git/maas into -b master lp:~maas-committers/maas
-b lp-2046255-
STATUS: FAILED maas-ci. internal: 8080/job/ maas-tester/ 4250/console 5684a818261ff68 cd3a909b84
LOG: http://
COMMIT: 7ef226238eada3d