Merge lp:~blake-rouse/maas/dns-triggers into lp:~maas-committers/maas/trunk

Proposed by Blake Rouse
Status: Merged
Approved by: Blake Rouse
Approved revision: no longer in the source branch.
Merged at revision: 4852
Proposed branch: lp:~blake-rouse/maas/dns-triggers
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 1170 lines (+1023/-11)
6 files modified
src/maasserver/sequence.py (+21/-2)
src/maasserver/tests/test_sequence.py (+2/-2)
src/maasserver/triggers/system.py (+244/-0)
src/maasserver/triggers/tests/helper.py (+23/-0)
src/maasserver/triggers/tests/test_system.py (+36/-6)
src/maasserver/triggers/tests/test_system_listener.py (+697/-1)
To merge this branch: bzr merge lp:~blake-rouse/maas/dns-triggers
Reviewer Review Type Date Requested Status
Blake Rouse (community) Approve
Mike Pontillo Pending
Review via email: mp+290383@code.launchpad.net

This proposal supersedes a proposal from 2016-03-25.

Commit message

Add triggers for the DNS HA system.

To post a comment you must log in.
Revision history for this message
LaMont Jones (lamont) wrote : Posted in a previous version of this proposal

Nothing leaps out at me in this, screaming "fix me!"

Revision history for this message
Mike Pontillo (mpontillo) wrote : Posted in a previous version of this proposal

Looks pretty good, but please see my questions below regarding a possible race condition when getting the first value from a sequence.

And some general gripes about triggers and trigger registration.

review: Approve
Revision history for this message
Blake Rouse (blake-rouse) : Posted in a previous version of this proposal
Revision history for this message
MAAS Lander (maas-lander) wrote : Posted in a previous version of this proposal

There are additional revisions which have not been approved in review. Please seek review and approval of these new revisions.

Revision history for this message
Blake Rouse (blake-rouse) wrote :

Had to resubmit because launchpad said it was still analyzing the diff that I pushed 4 hours ago.

review: Approve
Revision history for this message
MAAS Lander (maas-lander) wrote :
Download full text (33.6 KiB)

The attempt to merge lp:~blake-rouse/maas/dns-triggers into lp:maas failed. Below is the output from the failed tests.

Hit:1 http://security.ubuntu.com/ubuntu xenial-security InRelease
Get:2 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial InRelease [116 kB]
Hit:3 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-updates InRelease
Hit:4 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-backports InRelease
Get:5 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial/universe Sources [7,517 kB]
Get:6 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial/universe amd64 Packages [7,249 kB]
Get:7 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial/universe Translation-en [4,188 kB]
Fetched 19.1 MB in 3s (5,787 kB/s)
Reading package lists...
sudo DEBIAN_FRONTEND=noninteractive apt-get -y \
    --no-install-recommends install apache2 archdetect-deb authbind bind9 bind9utils build-essential bzr-builddeb chromium-browser chromium-chromedriver curl daemontools debhelper dh-apport dh-systemd distro-info dnsutils firefox freeipmi-tools git gjs ipython isc-dhcp-common libjs-angularjs libjs-jquery libjs-jquery-hotkeys libjs-yui3-full libjs-yui3-min libpq-dev make nodejs-legacy npm postgresql pxelinux python3-all python3-apt python3-bson python3-convoy python3-coverage python3-crochet python3-cssselect python3-curtin python3-dev python3-distro-info python3-django python3-django-nose python3-django-piston3 python3-dnspython python3-docutils python3-formencode python3-hivex python3-httplib2 python3-jinja2 python3-jsonschema python3-lxml python3-mock python3-netaddr python3-netifaces python3-oauth python3-oauthlib python3-openssl python3-paramiko python3-petname python3-pexpect python3-psycopg2 python3-pyinotify python3-pyparsing python3-pyvmomi python3-requests python3-seamicroclient python3-setuptools python3-simplestreams python3-sphinx python3-tempita python3-twisted python3-txtftp python3-tz python3-yaml python3-zope.interface python-bson python-crochet python-django python-django-piston python-djorm-ext-pgarray python-formencode python-lxml python-netaddr python-netifaces python-pocket-lint python-psycopg2 python-tempita python-twisted python-yaml socat syslinux-common tgt ubuntu-cloudimage-keyring wget xvfb
Reading package lists...
Building dependency tree...
Reading state information...
apache2 is already the newest version (2.4.18-1ubuntu1).
archdetect-deb is already the newest version (1.114ubuntu4).
authbind is already the newest version (2.1.1+nmu1).
bind9 is already the newest version (1:9.10.3.dfsg.P4-5).
bind9utils is already the newest version (1:9.10.3.dfsg.P4-5).
build-essential is already the newest version (12.1ubuntu2).
curl is already the newest version (7.47.0-1ubuntu2).
debhelper is already the newest version (9.20160115ubuntu2).
dh-apport is already the newest version (2.20-0ubuntu3).
dh-systemd is already the newest version (1.29ubuntu1).
distro-info is already the newest version (0.14build1).
dnsutils is already the newest version (1:9.10.3.dfsg.P4-5).
firefox is already the newest version (45.0.1+build1-0ubuntu1).
freeipmi-tools is already the newest version ...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/maasserver/sequence.py'
2--- src/maasserver/sequence.py 2016-03-25 14:52:23 +0000
3+++ src/maasserver/sequence.py 2016-03-30 13:52:37 +0000
4@@ -20,6 +20,7 @@
5 from provisioningserver.utils import typed
6 from psycopg2.errorcodes import (
7 DUPLICATE_TABLE,
8+ NUMERIC_VALUE_OUT_OF_RANGE,
9 OBJECT_NOT_IN_PREREQUISITE_STATE,
10 UNDEFINED_TABLE,
11 )
12@@ -169,8 +170,26 @@
13 return cursor.fetchone()[0]
14 except (utils.OperationalError, utils.ProgrammingError) as error:
15 if is_postgres_error(error, OBJECT_NOT_IN_PREREQUISITE_STATE):
16- # There is no current value for the sequence.
17- return None
18+ # There is no current value for the sequence in this session.
19+ # Perform nextval with setval to follow so we can get the
20+ # current value of the sequence.
21+ try:
22+ with transaction.atomic():
23+ with connection.cursor() as cursor:
24+ cursor.execute(
25+ "SELECT setval(%s, nextval(%s) - %s);",
26+ [self.name, self.name, self.increment])
27+ cursor.execute("SELECT currval(%s)", [self.name])
28+ return cursor.fetchone()[0]
29+ except utils.DataError as error:
30+ if is_postgres_error(error, NUMERIC_VALUE_OUT_OF_RANGE):
31+ # The sequence was just created so calling nextval,
32+ # minusing the interval is placing it below the
33+ # minimum. The current value is the minimum.
34+ return (
35+ self.minvalue if self.minvalue is not None else 1)
36+ else:
37+ raise
38 elif is_postgres_error(error, UNDEFINED_TABLE):
39 # The sequence does not exist, hence has no current value.
40 return None
41
42=== modified file 'src/maasserver/tests/test_sequence.py'
43--- src/maasserver/tests/test_sequence.py 2016-03-25 14:52:23 +0000
44+++ src/maasserver/tests/test_sequence.py 2016-03-30 13:52:37 +0000
45@@ -157,11 +157,11 @@
46 seq = Sequence(name)
47 self.assertEqual(None, seq.current())
48
49- def test_current_returns_none_when_no_current_value(self):
50+ def test_current_returns_minimum_value_when_no_current_value(self):
51 name = factory.make_name('seq', sep='')
52 seq = Sequence(name)
53 seq.create()
54- self.assertEqual(None, seq.current())
55+ self.assertEqual(1, seq.current())
56
57 def test_current_returns_current_value(self):
58 name = factory.make_name('seq', sep='')
59
60=== modified file 'src/maasserver/triggers/system.py'
61--- src/maasserver/triggers/system.py 2016-03-25 14:52:23 +0000
62+++ src/maasserver/triggers/system.py 2016-03-30 13:52:37 +0000
63@@ -15,6 +15,7 @@
64
65 from textwrap import dedent
66
67+from maasserver.dns.config import zone_serial
68 from maasserver.triggers import (
69 register_procedure,
70 register_trigger,
71@@ -781,6 +782,122 @@
72 $$ LANGUAGE plpgsql;
73 """)
74
75+# Triggered when a subnet is updated. Increments the zone serial and notifies
76+# that DNS needs to be updated. Only watches changes on the cidr and rdns_mode.
77+DNS_SUBNET_UPDATE = dedent("""\
78+ CREATE OR REPLACE FUNCTION sys_dns_subnet_update()
79+ RETURNS trigger as $$
80+ BEGIN
81+ IF OLD.cidr != NEW.cidr OR OLD.rdns_mode != NEW.rdns_mode THEN
82+ -- Increment the zone serial.
83+ PERFORM nextval('maasserver_zone_serial_seq');
84+ PERFORM pg_notify('sys_dns', '');
85+ END IF;
86+ RETURN NEW;
87+ END;
88+ $$ LANGUAGE plpgsql;
89+ """)
90+
91+# Triggered when a node is updated. Increments the zone serial and notifies
92+# that DNS needs to be updated. Only watches changes on the hostname and
93+# linked domain for the node.
94+DNS_NODE_UPDATE = dedent("""\
95+ CREATE OR REPLACE FUNCTION sys_dns_node_update()
96+ RETURNS trigger as $$
97+ BEGIN
98+ IF OLD.hostname != NEW.hostname OR OLD.domain_id != NEW.domain_id THEN
99+ -- Increment the zone serial.
100+ PERFORM nextval('maasserver_zone_serial_seq');
101+ PERFORM pg_notify('sys_dns', '');
102+ END IF;
103+ RETURN NEW;
104+ END;
105+ $$ LANGUAGE plpgsql;
106+ """)
107+
108+
109+# Triggered when a interface is updated. Increments the zone serial and
110+# notifies that DNS needs to be updated. Only watches changes on the name and
111+# the node that the interface belongs to.
112+DNS_INTERFACE_UPDATE = dedent("""\
113+ CREATE OR REPLACE FUNCTION sys_dns_interface_update()
114+ RETURNS trigger as $$
115+ BEGIN
116+ IF (OLD.name != NEW.name OR
117+ (OLD.node_id IS NULL AND NEW.node_id IS NOT NULL) OR
118+ (OLD.node_id IS NOT NULL AND NEW.node_id IS NULL) OR
119+ (OLD.node_id != NEW.node_id)) THEN
120+ -- Increment the zone serial.
121+ PERFORM nextval('maasserver_zone_serial_seq');
122+ PERFORM pg_notify('sys_dns', '');
123+ END IF;
124+ RETURN NEW;
125+ END;
126+ $$ LANGUAGE plpgsql;
127+ """)
128+
129+
130+# Triggered when a config is inserted. Increments the zone serial and notifies
131+# that DNS needs to be updated. Only watches for inserts on config
132+# upstream_dns, default_dns_ttl, and windows_kms_host.
133+DNS_CONFIG_INSERT = dedent("""\
134+ CREATE OR REPLACE FUNCTION sys_dns_config_insert()
135+ RETURNS trigger as $$
136+ BEGIN
137+ -- Only care about the
138+ IF (NEW.name = 'upstream_dns' OR
139+ NEW.name = 'default_dns_ttl' OR
140+ NEW.name = 'windows_kms_host') THEN
141+ -- Increment the zone serial.
142+ PERFORM nextval('maasserver_zone_serial_seq');
143+ PERFORM pg_notify('sys_dns', '');
144+ END IF;
145+ RETURN NEW;
146+ END;
147+ $$ LANGUAGE plpgsql;
148+ """)
149+
150+# Triggered when a config is updated. Increments the zone serial and notifies
151+# that DNS needs to be updated. Only watches for updates on config
152+# upstream_dns, default_dns_ttl, and windows_kms_host.
153+DNS_CONFIG_UPDATE = dedent("""\
154+ CREATE OR REPLACE FUNCTION sys_dns_config_update()
155+ RETURNS trigger as $$
156+ BEGIN
157+ -- Only care about the upstream_dns, default_dns_ttl, and
158+ -- windows_kms_host.
159+ IF (OLD.value != NEW.value AND (
160+ NEW.name = 'upstream_dns' OR
161+ NEW.name = 'default_dns_ttl' OR
162+ NEW.name = 'windows_kms_host')) THEN
163+ -- Increment the zone serial.
164+ PERFORM nextval('maasserver_zone_serial_seq');
165+ PERFORM pg_notify('sys_dns', '');
166+ END IF;
167+ RETURN NEW;
168+ END;
169+ $$ LANGUAGE plpgsql;
170+ """)
171+
172+
173+def render_sys_dns_procedure(proc_name, on_delete=False):
174+ """Render a database procedure with name `proc_name` that increments
175+ the zone serial and notifies that a DNS update is needed.
176+
177+ :param proc_name: Name of the procedure.
178+ :param on_delete: True when procedure will be used as a delete trigger.
179+ """
180+ return dedent("""\
181+ CREATE OR REPLACE FUNCTION %s() RETURNS trigger AS $$
182+ BEGIN
183+ -- Increment the zone serial.
184+ PERFORM nextval('maasserver_zone_serial_seq');
185+ PERFORM pg_notify('sys_dns', '');
186+ RETURN %s;
187+ END;
188+ $$ LANGUAGE plpgsql;
189+ """ % (proc_name, 'NEW' if not on_delete else 'OLD'))
190+
191
192 @transactional
193 def register_system_triggers():
194@@ -871,3 +988,130 @@
195 register_procedure(DHCP_SNIPPET_DELETE)
196 register_trigger(
197 "maasserver_dhcpsnippet", "sys_dhcp_snippet_delete", "delete")
198+
199+ # DNS
200+ # The zone serial is used in the 'sys_dns' triggers. Ensure that it exists
201+ # before creating the triggers.
202+ zone_serial.create_if_not_exists()
203+
204+ ## Domain
205+ register_procedure(
206+ render_sys_dns_procedure("sys_dns_domain_insert"))
207+ register_trigger(
208+ "maasserver_domain", "sys_dns_domain_insert", "insert")
209+ register_procedure(
210+ render_sys_dns_procedure("sys_dns_domain_update"))
211+ register_trigger(
212+ "maasserver_domain", "sys_dns_domain_update", "update")
213+ register_procedure(
214+ render_sys_dns_procedure("sys_dns_domain_delete", on_delete=True))
215+ register_trigger(
216+ "maasserver_domain", "sys_dns_domain_delete", "delete")
217+
218+ ## StaticIPAddress
219+ register_procedure(
220+ render_sys_dns_procedure("sys_dns_staticipaddress_update"))
221+ register_trigger(
222+ "maasserver_staticipaddress",
223+ "sys_dns_staticipaddress_update", "update")
224+
225+ ## Interface -> StaticIPAddress
226+ register_procedure(
227+ render_sys_dns_procedure("sys_dns_nic_ip_link"))
228+ register_trigger(
229+ "maasserver_interface_ip_addresses",
230+ "sys_dns_nic_ip_link", "insert")
231+ register_procedure(
232+ render_sys_dns_procedure(
233+ "sys_dns_nic_ip_unlink", on_delete=True))
234+ register_trigger(
235+ "maasserver_interface_ip_addresses",
236+ "sys_dns_nic_ip_unlink", "delete")
237+
238+ ## DNSResource
239+ register_procedure(
240+ render_sys_dns_procedure("sys_dns_dnsresource_insert"))
241+ register_trigger(
242+ "maasserver_dnsresource",
243+ "sys_dns_dnsresource_insert", "insert")
244+ register_procedure(
245+ render_sys_dns_procedure("sys_dns_dnsresource_update"))
246+ register_trigger(
247+ "maasserver_dnsresource",
248+ "sys_dns_dnsresource_update", "update")
249+ register_procedure(
250+ render_sys_dns_procedure("sys_dns_dnsresource_delete", on_delete=True))
251+ register_trigger(
252+ "maasserver_dnsresource",
253+ "sys_dns_dnsresource_delete", "delete")
254+
255+ ## DNSResource -> StaticIPAddress
256+ register_procedure(
257+ render_sys_dns_procedure("sys_dns_dnsresource_ip_link"))
258+ register_trigger(
259+ "maasserver_dnsresource_ip_addresses",
260+ "sys_dns_dnsresource_ip_link", "insert")
261+ register_procedure(
262+ render_sys_dns_procedure(
263+ "sys_dns_dnsresource_ip_unlink", on_delete=True))
264+ register_trigger(
265+ "maasserver_dnsresource_ip_addresses",
266+ "sys_dns_dnsresource_ip_unlink", "delete")
267+
268+ ## DNSData
269+ register_procedure(
270+ render_sys_dns_procedure("sys_dns_dnsdata_insert"))
271+ register_trigger(
272+ "maasserver_dnsdata",
273+ "sys_dns_dnsdata_insert", "insert")
274+ register_procedure(
275+ render_sys_dns_procedure("sys_dns_dnsdata_update"))
276+ register_trigger(
277+ "maasserver_dnsdata",
278+ "sys_dns_dnsdata_update", "update")
279+ register_procedure(
280+ render_sys_dns_procedure("sys_dns_dnsdata_delete", on_delete=True))
281+ register_trigger(
282+ "maasserver_dnsdata",
283+ "sys_dns_dnsdata_delete", "delete")
284+
285+ ## Subnet
286+ register_procedure(
287+ render_sys_dns_procedure("sys_dns_subnet_insert"))
288+ register_trigger(
289+ "maasserver_subnet",
290+ "sys_dns_subnet_insert", "insert")
291+ register_procedure(DNS_SUBNET_UPDATE)
292+ register_trigger(
293+ "maasserver_subnet",
294+ "sys_dns_subnet_update", "update")
295+ register_procedure(
296+ render_sys_dns_procedure("sys_dns_subnet_delete", on_delete=True))
297+ register_trigger(
298+ "maasserver_subnet",
299+ "sys_dns_subnet_delete", "delete")
300+
301+ ## Node
302+ register_procedure(DNS_NODE_UPDATE)
303+ register_trigger(
304+ "maasserver_node",
305+ "sys_dns_node_update", "update")
306+ register_procedure(
307+ render_sys_dns_procedure("sys_dns_node_delete", on_delete=True))
308+ register_trigger(
309+ "maasserver_node",
310+ "sys_dns_node_delete", "delete")
311+
312+ ## Interface
313+ register_procedure(DNS_INTERFACE_UPDATE)
314+ register_trigger(
315+ "maasserver_interface",
316+ "sys_dns_interface_update", "update")
317+
318+ ## Config
319+ register_procedure(DNS_CONFIG_INSERT)
320+ register_procedure(DNS_CONFIG_UPDATE)
321+ register_trigger(
322+ "maasserver_config", "sys_dns_config_insert", "insert")
323+ register_trigger(
324+ "maasserver_config", "sys_dns_config_update", "update")
325
326=== modified file 'src/maasserver/triggers/tests/helper.py'
327--- src/maasserver/triggers/tests/helper.py 2016-03-29 17:02:00 +0000
328+++ src/maasserver/triggers/tests/helper.py 2016-03-30 13:52:37 +0000
329@@ -8,6 +8,7 @@
330
331 from crochet import wait_for
332 from django.contrib.auth.models import User
333+from maasserver.dns.config import zone_serial
334 from maasserver.enum import (
335 INTERFACE_TYPE,
336 NODE_TYPE,
337@@ -52,7 +53,9 @@
338 reload_object,
339 transactional,
340 )
341+from maasserver.utils.threads import deferToDatabase
342 from metadataserver.models import NodeResult
343+from twisted.internet.defer import inlineCallbacks
344
345
346 wait_for_reactor = wait_for(30) # 30 seconds.
347@@ -365,6 +368,12 @@
348 return factory.make_Interface(INTERFACE_TYPE.PHYSICAL, **params)
349
350 @transactional
351+ def create_unknown_interface(self, params=None):
352+ if params is None:
353+ params = {}
354+ return factory.make_Interface(INTERFACE_TYPE.UNKNOWN, **params)
355+
356+ @transactional
357 def delete_interface(self, id):
358 interface = Interface.objects.get(id=id)
359 interface.delete()
360@@ -624,3 +633,17 @@
361 @transactional
362 def reload_object(self, obj):
363 return reload_object(obj)
364+
365+
366+class DNSHelpersMixin:
367+ """Helper to get the zone serial and to assert it was incremented."""
368+
369+ def get_zone_serial_current(self):
370+ return deferToDatabase(transactional(zone_serial.current))
371+
372+ @inlineCallbacks
373+ def assertZoneSerialIncrement(self, previous):
374+ current = yield deferToDatabase(transactional(zone_serial.current))
375+ self.assertTrue(
376+ current > previous,
377+ "Zone serial was not incremented.")
378
379=== modified file 'src/maasserver/triggers/tests/test_system.py'
380--- src/maasserver/triggers/tests/test_system.py 2016-02-10 20:24:35 +0000
381+++ src/maasserver/triggers/tests/test_system.py 2016-03-30 13:52:37 +0000
382@@ -8,9 +8,11 @@
383 from contextlib import closing
384
385 from django.db import connection
386+from maasserver.dns.config import zone_serial
387 from maasserver.testing.testcase import MAASServerTestCase
388 from maasserver.triggers.system import register_system_triggers
389 from maasserver.utils.orm import psql_array
390+from maastesting.matchers import MockCalledOnceWith
391
392
393 class TestTriggers(MAASServerTestCase):
394@@ -31,6 +33,28 @@
395 "staticipaddress_sys_dhcp_staticipaddress_delete",
396 "interface_sys_dhcp_interface_update",
397 "node_sys_dhcp_node_update",
398+ "dhcpsnippet_sys_dhcp_snippet_insert",
399+ "dhcpsnippet_sys_dhcp_snippet_update",
400+ "dhcpsnippet_sys_dhcp_snippet_delete",
401+ "domain_sys_dns_domain_insert",
402+ "domain_sys_dns_domain_update",
403+ "domain_sys_dns_domain_delete",
404+ "staticipaddress_sys_dns_staticipaddress_update",
405+ "interface_ip_addresses_sys_dns_nic_ip_link",
406+ "interface_ip_addresses_sys_dns_nic_ip_unlink",
407+ "dnsresource_sys_dns_dnsresource_insert",
408+ "dnsresource_sys_dns_dnsresource_update",
409+ "dnsresource_sys_dns_dnsresource_delete",
410+ "dnsresource_ip_addresses_sys_dns_dnsresource_ip_link",
411+ "dnsresource_ip_addresses_sys_dns_dnsresource_ip_unlink",
412+ "dnsdata_sys_dns_dnsdata_insert",
413+ "dnsdata_sys_dns_dnsdata_update",
414+ "dnsdata_sys_dns_dnsdata_delete",
415+ "node_sys_dns_node_update",
416+ "node_sys_dns_node_delete",
417+ "interface_sys_dns_interface_update",
418+ "config_sys_dns_config_insert",
419+ "config_sys_dns_config_update",
420 ]
421 sql, args = psql_array(triggers, sql_type="text")
422 with closing(connection.cursor()) as cursor:
423@@ -42,12 +66,18 @@
424 # Note: if this test fails, a trigger may have been added, but not
425 # added to the list of expected triggers.
426 triggers_found = [trigger[0] for trigger in db_triggers]
427+ missing_triggers = [
428+ trigger
429+ for trigger in triggers
430+ if trigger not in triggers_found
431+ ]
432 self.assertEqual(
433 len(triggers), len(db_triggers),
434- "Missing %s triggers in the database. Triggers found: %s" % (
435- len(triggers) - len(db_triggers), triggers_found))
436+ "Missing %s triggers in the database. Triggers missing: %s" % (
437+ len(triggers) - len(db_triggers), missing_triggers))
438
439- self.assertItemsEqual(
440- triggers, triggers_found,
441- "Missing triggers in the database. Triggers found: %s" % (
442- triggers_found))
443+ def test_register_system_triggers_ensures_zone_serial(self):
444+ mock_create = self.patch(
445+ zone_serial, "create_if_not_exists")
446+ register_system_triggers()
447+ self.assertThat(mock_create, MockCalledOnceWith())
448
449=== modified file 'src/maasserver/triggers/tests/test_system_listener.py'
450--- src/maasserver/triggers/tests/test_system_listener.py 2016-03-25 14:52:23 +0000
451+++ src/maasserver/triggers/tests/test_system_listener.py 2016-03-30 13:52:37 +0000
452@@ -10,17 +10,29 @@
453 datetime,
454 timedelta,
455 )
456+import random
457
458 from crochet import wait_for
459 from django.db import connection as db_connection
460 from maasserver.enum import (
461+ INTERFACE_TYPE,
462 IPADDRESS_TYPE,
463 IPRANGE_TYPE,
464+ RDNS_MODE,
465+)
466+from maasserver.models.config import Config
467+from maasserver.models.interface import (
468+ Interface,
469+ PhysicalInterface,
470+ UnknownInterface,
471 )
472 from maasserver.testing.factory import factory
473 from maasserver.testing.testcase import MAASTransactionServerTestCase
474 from maasserver.triggers.system import register_system_triggers
475-from maasserver.triggers.tests.helper import TransactionalHelpersMixin
476+from maasserver.triggers.tests.helper import (
477+ DNSHelpersMixin,
478+ TransactionalHelpersMixin,
479+)
480 from maasserver.utils.orm import transactional
481 from maasserver.utils.threads import deferToDatabase
482 from netaddr import IPAddress
483@@ -2270,3 +2282,687 @@
484 yield dv.get(timeout=2)
485 finally:
486 yield listener.stopService()
487+
488+
489+class TestDNSDomainListener(
490+ MAASTransactionServerTestCase, TransactionalHelpersMixin,
491+ DNSHelpersMixin):
492+ """End-to-end test for the DNS triggers code."""
493+
494+ @wait_for_reactor
495+ @inlineCallbacks
496+ def test_sends_message_for_domain_insert(self):
497+ yield deferToDatabase(register_system_triggers)
498+ zone_serial = yield self.get_zone_serial_current()
499+ dv = DeferredValue()
500+ listener = self.make_listener_without_delay()
501+ listener.register(
502+ "sys_dns", lambda *args: dv.set(args))
503+ yield listener.startService()
504+ try:
505+ yield deferToDatabase(self.create_domain)
506+ yield dv.get(timeout=2)
507+ yield self.assertZoneSerialIncrement(zone_serial)
508+ finally:
509+ yield listener.stopService()
510+
511+ @wait_for_reactor
512+ @inlineCallbacks
513+ def test_sends_message_for_domain_update(self):
514+ yield deferToDatabase(register_system_triggers)
515+ domain = yield deferToDatabase(self.create_domain)
516+ zone_serial = yield self.get_zone_serial_current()
517+ dv = DeferredValue()
518+ listener = self.make_listener_without_delay()
519+ listener.register(
520+ "sys_dns", lambda *args: dv.set(args))
521+ yield listener.startService()
522+ try:
523+ yield deferToDatabase(self.update_domain, domain.id, {
524+ "name": factory.make_name("domain"),
525+ })
526+ yield dv.get(timeout=2)
527+ yield self.assertZoneSerialIncrement(zone_serial)
528+ finally:
529+ yield listener.stopService()
530+
531+ @wait_for_reactor
532+ @inlineCallbacks
533+ def test_sends_message_for_domain_delete(self):
534+ yield deferToDatabase(register_system_triggers)
535+ domain = yield deferToDatabase(self.create_domain)
536+ zone_serial = yield self.get_zone_serial_current()
537+ dv = DeferredValue()
538+ listener = self.make_listener_without_delay()
539+ listener.register(
540+ "sys_dns", lambda *args: dv.set(args))
541+ yield listener.startService()
542+ try:
543+ yield deferToDatabase(self.delete_domain, domain.id)
544+ yield dv.get(timeout=2)
545+ yield self.assertZoneSerialIncrement(zone_serial)
546+ finally:
547+ yield listener.stopService()
548+
549+
550+class TestDNSStaticIPAddressListener(
551+ MAASTransactionServerTestCase, TransactionalHelpersMixin,
552+ DNSHelpersMixin):
553+ """End-to-end test for the DNS triggers code."""
554+
555+ @wait_for_reactor
556+ @inlineCallbacks
557+ def test_sends_message_for_staticipaddress_update(self):
558+ yield deferToDatabase(register_system_triggers)
559+ sip = yield deferToDatabase(self.create_staticipaddress)
560+ zone_serial = yield self.get_zone_serial_current()
561+ dv = DeferredValue()
562+ listener = self.make_listener_without_delay()
563+ listener.register(
564+ "sys_dns", lambda *args: dv.set(args))
565+ yield listener.startService()
566+ try:
567+ yield deferToDatabase(self.update_staticipaddress, sip.id, {
568+ "alloc_type": IPADDRESS_TYPE.STICKY,
569+ })
570+ yield dv.get(timeout=2)
571+ yield self.assertZoneSerialIncrement(zone_serial)
572+ finally:
573+ yield listener.stopService()
574+
575+
576+class TestDNSInterfaceStaticIPAddressListener(
577+ MAASTransactionServerTestCase, TransactionalHelpersMixin,
578+ DNSHelpersMixin):
579+ """End-to-end test for the DNS triggers code."""
580+
581+ @wait_for_reactor
582+ @inlineCallbacks
583+ def test_sends_message_for_interface_staticipaddress_link(self):
584+ yield deferToDatabase(register_system_triggers)
585+ interface = yield deferToDatabase(self.create_interface)
586+ zone_serial = yield self.get_zone_serial_current()
587+ dv = DeferredValue()
588+ listener = self.make_listener_without_delay()
589+ listener.register(
590+ "sys_dns", lambda *args: dv.set(args))
591+ yield listener.startService()
592+ try:
593+ yield deferToDatabase(self.create_staticipaddress, {
594+ "interface": interface,
595+ })
596+ yield dv.get(timeout=2)
597+ yield self.assertZoneSerialIncrement(zone_serial)
598+ finally:
599+ yield listener.stopService()
600+
601+ @wait_for_reactor
602+ @inlineCallbacks
603+ def test_sends_message_for_interface_staticipaddress_unlink(self):
604+ yield deferToDatabase(register_system_triggers)
605+ interface = yield deferToDatabase(self.create_interface)
606+ sip = yield deferToDatabase(self.create_staticipaddress, {
607+ "interface": interface,
608+ })
609+ zone_serial = yield self.get_zone_serial_current()
610+ dv = DeferredValue()
611+ listener = self.make_listener_without_delay()
612+ listener.register(
613+ "sys_dns", lambda *args: dv.set(args))
614+ yield listener.startService()
615+ try:
616+ yield deferToDatabase(self.delete_staticipaddress, sip.id)
617+ yield dv.get(timeout=2)
618+ yield self.assertZoneSerialIncrement(zone_serial)
619+ finally:
620+ yield listener.stopService()
621+
622+
623+class TestDNSDNSResourceListener(
624+ MAASTransactionServerTestCase, TransactionalHelpersMixin,
625+ DNSHelpersMixin):
626+ """End-to-end test for the DNS triggers code."""
627+
628+ @wait_for_reactor
629+ @inlineCallbacks
630+ def test_sends_message_for_dnsresource_insert(self):
631+ yield deferToDatabase(register_system_triggers)
632+ zone_serial = yield self.get_zone_serial_current()
633+ dv = DeferredValue()
634+ listener = self.make_listener_without_delay()
635+ listener.register(
636+ "sys_dns", lambda *args: dv.set(args))
637+ yield listener.startService()
638+ try:
639+ yield deferToDatabase(self.create_dnsresource)
640+ yield dv.get(timeout=2)
641+ yield self.assertZoneSerialIncrement(zone_serial)
642+ finally:
643+ yield listener.stopService()
644+
645+ @wait_for_reactor
646+ @inlineCallbacks
647+ def test_sends_message_for_dnsresource_update(self):
648+ yield deferToDatabase(register_system_triggers)
649+ resource = yield deferToDatabase(self.create_dnsresource)
650+ zone_serial = yield self.get_zone_serial_current()
651+ dv = DeferredValue()
652+ listener = self.make_listener_without_delay()
653+ listener.register(
654+ "sys_dns", lambda *args: dv.set(args))
655+ yield listener.startService()
656+ try:
657+ yield deferToDatabase(self.update_dnsresource, resource.id, {
658+ "name": factory.make_name("resource"),
659+ })
660+ yield dv.get(timeout=2)
661+ yield self.assertZoneSerialIncrement(zone_serial)
662+ finally:
663+ yield listener.stopService()
664+
665+ @wait_for_reactor
666+ @inlineCallbacks
667+ def test_sends_message_for_dnsresource_delete(self):
668+ yield deferToDatabase(register_system_triggers)
669+ resource = yield deferToDatabase(self.create_dnsresource)
670+ zone_serial = yield self.get_zone_serial_current()
671+ dv = DeferredValue()
672+ listener = self.make_listener_without_delay()
673+ listener.register(
674+ "sys_dns", lambda *args: dv.set(args))
675+ yield listener.startService()
676+ try:
677+ yield deferToDatabase(self.delete_dnsresource, resource.id)
678+ yield dv.get(timeout=2)
679+ yield self.assertZoneSerialIncrement(zone_serial)
680+ finally:
681+ yield listener.stopService()
682+
683+
684+class TestDNSDNSResourceStaticIPAddressListener(
685+ MAASTransactionServerTestCase, TransactionalHelpersMixin,
686+ DNSHelpersMixin):
687+ """End-to-end test for the DNS triggers code."""
688+
689+ @wait_for_reactor
690+ @inlineCallbacks
691+ def test_sends_message_for_dnsresource_staticipaddress_link(self):
692+ yield deferToDatabase(register_system_triggers)
693+ resource = yield deferToDatabase(self.create_dnsresource)
694+ sip = yield deferToDatabase(self.create_staticipaddress)
695+ zone_serial = yield self.get_zone_serial_current()
696+ dv = DeferredValue()
697+ listener = self.make_listener_without_delay()
698+ listener.register(
699+ "sys_dns", lambda *args: dv.set(args))
700+ yield listener.startService()
701+ try:
702+ yield deferToDatabase(resource.ip_addresses.add, sip)
703+ yield dv.get(timeout=2)
704+ yield self.assertZoneSerialIncrement(zone_serial)
705+ finally:
706+ yield listener.stopService()
707+
708+ @wait_for_reactor
709+ @inlineCallbacks
710+ def test_sends_message_for_dnsresource_staticipaddress_unlink(self):
711+ yield deferToDatabase(register_system_triggers)
712+ resource = yield deferToDatabase(self.create_dnsresource)
713+ sip = yield deferToDatabase(self.create_staticipaddress)
714+ yield deferToDatabase(resource.ip_addresses.add, sip)
715+ zone_serial = yield self.get_zone_serial_current()
716+ dv = DeferredValue()
717+ listener = self.make_listener_without_delay()
718+ listener.register(
719+ "sys_dns", lambda *args: dv.set(args))
720+ yield listener.startService()
721+ try:
722+ yield deferToDatabase(resource.ip_addresses.remove, sip)
723+ yield dv.get(timeout=2)
724+ yield self.assertZoneSerialIncrement(zone_serial)
725+ finally:
726+ yield listener.stopService()
727+
728+
729+class TestDNSDNSDataListener(
730+ MAASTransactionServerTestCase, TransactionalHelpersMixin,
731+ DNSHelpersMixin):
732+ """End-to-end test for the DNS triggers code."""
733+
734+ @wait_for_reactor
735+ @inlineCallbacks
736+ def test_sends_message_for_dnsdata_insert(self):
737+ yield deferToDatabase(register_system_triggers)
738+ zone_serial = yield self.get_zone_serial_current()
739+ dv = DeferredValue()
740+ listener = self.make_listener_without_delay()
741+ listener.register(
742+ "sys_dns", lambda *args: dv.set(args))
743+ yield listener.startService()
744+ try:
745+ yield deferToDatabase(self.create_dnsdata)
746+ yield dv.get(timeout=2)
747+ yield self.assertZoneSerialIncrement(zone_serial)
748+ finally:
749+ yield listener.stopService()
750+
751+ @wait_for_reactor
752+ @inlineCallbacks
753+ def test_sends_message_for_dnsdata_update(self):
754+ yield deferToDatabase(register_system_triggers)
755+ data = yield deferToDatabase(self.create_dnsdata, {
756+ "rrtype": "TXT",
757+ "rrdata": factory.make_name("txt"),
758+ })
759+ zone_serial = yield self.get_zone_serial_current()
760+ dv = DeferredValue()
761+ listener = self.make_listener_without_delay()
762+ listener.register(
763+ "sys_dns", lambda *args: dv.set(args))
764+ yield listener.startService()
765+ try:
766+ yield deferToDatabase(self.update_dnsdata, data.id, {
767+ "rrdata": factory.make_name("txt"),
768+ })
769+ yield dv.get(timeout=2)
770+ yield self.assertZoneSerialIncrement(zone_serial)
771+ finally:
772+ yield listener.stopService()
773+
774+ @wait_for_reactor
775+ @inlineCallbacks
776+ def test_sends_message_for_dnsdata_delete(self):
777+ yield deferToDatabase(register_system_triggers)
778+ data = yield deferToDatabase(self.create_dnsdata)
779+ zone_serial = yield self.get_zone_serial_current()
780+ dv = DeferredValue()
781+ listener = self.make_listener_without_delay()
782+ listener.register(
783+ "sys_dns", lambda *args: dv.set(args))
784+ yield listener.startService()
785+ try:
786+ yield deferToDatabase(self.delete_dnsdata, data.id)
787+ yield dv.get(timeout=2)
788+ yield self.assertZoneSerialIncrement(zone_serial)
789+ finally:
790+ yield listener.stopService()
791+
792+
793+class TestDNSSubnetListener(
794+ MAASTransactionServerTestCase, TransactionalHelpersMixin,
795+ DNSHelpersMixin):
796+ """End-to-end test for the DNS triggers code."""
797+
798+ @wait_for_reactor
799+ @inlineCallbacks
800+ def test_sends_message_for_subnet_insert(self):
801+ yield deferToDatabase(register_system_triggers)
802+ zone_serial = yield self.get_zone_serial_current()
803+ dv = DeferredValue()
804+ listener = self.make_listener_without_delay()
805+ listener.register(
806+ "sys_dns", lambda *args: dv.set(args))
807+ yield listener.startService()
808+ try:
809+ yield deferToDatabase(self.create_subnet)
810+ yield dv.get(timeout=2)
811+ yield self.assertZoneSerialIncrement(zone_serial)
812+ finally:
813+ yield listener.stopService()
814+
815+ @wait_for_reactor
816+ @inlineCallbacks
817+ def test_sends_message_for_subnet_cidr_update(self):
818+ yield deferToDatabase(register_system_triggers)
819+ subnet = yield deferToDatabase(self.create_subnet)
820+ zone_serial = yield self.get_zone_serial_current()
821+ dv = DeferredValue()
822+ listener = self.make_listener_without_delay()
823+ listener.register(
824+ "sys_dns", lambda *args: dv.set(args))
825+ yield listener.startService()
826+ try:
827+ network = factory.make_ip4_or_6_network()
828+ yield deferToDatabase(self.update_subnet, subnet.id, {
829+ "cidr": str(network.cidr),
830+ "gateway_ip": factory.pick_ip_in_network(network),
831+ "dns_servers": [],
832+ })
833+ yield dv.get(timeout=2)
834+ yield self.assertZoneSerialIncrement(zone_serial)
835+ finally:
836+ yield listener.stopService()
837+
838+ @wait_for_reactor
839+ @inlineCallbacks
840+ def test_sends_message_for_subnet_rdns_mode_update(self):
841+ yield deferToDatabase(register_system_triggers)
842+ subnet = yield deferToDatabase(self.create_subnet)
843+ zone_serial = yield self.get_zone_serial_current()
844+ dv = DeferredValue()
845+ listener = self.make_listener_without_delay()
846+ listener.register(
847+ "sys_dns", lambda *args: dv.set(args))
848+ yield listener.startService()
849+ try:
850+ yield deferToDatabase(self.update_subnet, subnet.id, {
851+ "rdns_mode": factory.pick_enum(
852+ RDNS_MODE, but_not=[subnet.rdns_mode]),
853+ })
854+ yield dv.get(timeout=2)
855+ yield self.assertZoneSerialIncrement(zone_serial)
856+ finally:
857+ yield listener.stopService()
858+
859+ @wait_for_reactor
860+ @inlineCallbacks
861+ def test_sends_message_for_subnet_delete(self):
862+ yield deferToDatabase(register_system_triggers)
863+ subnet = yield deferToDatabase(self.create_subnet)
864+ zone_serial = yield self.get_zone_serial_current()
865+ dv = DeferredValue()
866+ listener = self.make_listener_without_delay()
867+ listener.register(
868+ "sys_dns", lambda *args: dv.set(args))
869+ yield listener.startService()
870+ try:
871+ yield deferToDatabase(self.delete_subnet, subnet.id)
872+ yield dv.get(timeout=2)
873+ yield self.assertZoneSerialIncrement(zone_serial)
874+ finally:
875+ yield listener.stopService()
876+
877+
878+class TestDNSNodeListener(
879+ MAASTransactionServerTestCase, TransactionalHelpersMixin,
880+ DNSHelpersMixin):
881+ """End-to-end test for the DNS triggers code."""
882+
883+ @wait_for_reactor
884+ @inlineCallbacks
885+ def test_sends_message_for_node_update_hostname(self):
886+ yield deferToDatabase(register_system_triggers)
887+ node = yield deferToDatabase(self.create_node)
888+ zone_serial = yield self.get_zone_serial_current()
889+ dv = DeferredValue()
890+ listener = self.make_listener_without_delay()
891+ listener.register(
892+ "sys_dns", lambda *args: dv.set(args))
893+ yield listener.startService()
894+ try:
895+ yield deferToDatabase(self.update_node, node.system_id, {
896+ "hostname": factory.make_name("hostname"),
897+ })
898+ yield dv.get(timeout=2)
899+ yield self.assertZoneSerialIncrement(zone_serial)
900+ finally:
901+ yield listener.stopService()
902+
903+ @wait_for_reactor
904+ @inlineCallbacks
905+ def test_sends_message_for_node_update_domain(self):
906+ yield deferToDatabase(register_system_triggers)
907+ node = yield deferToDatabase(self.create_node)
908+ domain = yield deferToDatabase(self.create_domain)
909+ zone_serial = yield self.get_zone_serial_current()
910+ dv = DeferredValue()
911+ listener = self.make_listener_without_delay()
912+ listener.register(
913+ "sys_dns", lambda *args: dv.set(args))
914+ yield listener.startService()
915+ try:
916+ yield deferToDatabase(self.update_node, node.system_id, {
917+ "domain": domain,
918+ })
919+ yield dv.get(timeout=2)
920+ yield self.assertZoneSerialIncrement(zone_serial)
921+ finally:
922+ yield listener.stopService()
923+
924+ @wait_for_reactor
925+ @inlineCallbacks
926+ def test_sends_message_for_node_delete(self):
927+ yield deferToDatabase(register_system_triggers)
928+ node = yield deferToDatabase(self.create_node)
929+ zone_serial = yield self.get_zone_serial_current()
930+ dv = DeferredValue()
931+ listener = self.make_listener_without_delay()
932+ listener.register(
933+ "sys_dns", lambda *args: dv.set(args))
934+ yield listener.startService()
935+ try:
936+ yield deferToDatabase(self.delete_node, node.system_id)
937+ yield dv.get(timeout=2)
938+ yield self.assertZoneSerialIncrement(zone_serial)
939+ finally:
940+ yield listener.stopService()
941+
942+
943+class TestDNSInterfaceListener(
944+ MAASTransactionServerTestCase, TransactionalHelpersMixin,
945+ DNSHelpersMixin):
946+ """End-to-end test for the DNS triggers code."""
947+
948+ @transactional
949+ def migrate_unknown_to_physical(self, id, node):
950+ nic = Interface.objects.get(id=id)
951+ nic.type = INTERFACE_TYPE.PHYSICAL
952+ nic.node = node
953+ nic.__class__ = PhysicalInterface
954+ nic.save()
955+
956+ @transactional
957+ def migrate_physical_to_unknown(self, id):
958+ nic = Interface.objects.get(id=id)
959+ nic.type = INTERFACE_TYPE.UNKNOWN
960+ nic.node = None
961+ nic.__class__ = UnknownInterface
962+ nic.save()
963+
964+ @wait_for_reactor
965+ @inlineCallbacks
966+ def test_sends_message_for_interface_update_name(self):
967+ yield deferToDatabase(register_system_triggers)
968+ interface = yield deferToDatabase(self.create_interface)
969+ zone_serial = yield self.get_zone_serial_current()
970+ dv = DeferredValue()
971+ listener = self.make_listener_without_delay()
972+ listener.register(
973+ "sys_dns", lambda *args: dv.set(args))
974+ yield listener.startService()
975+ try:
976+ yield deferToDatabase(self.update_interface, interface.id, {
977+ "name": factory.make_name("name"),
978+ })
979+ yield dv.get(timeout=2)
980+ yield self.assertZoneSerialIncrement(zone_serial)
981+ finally:
982+ yield listener.stopService()
983+
984+ @wait_for_reactor
985+ @inlineCallbacks
986+ def test_sends_message_for_unknown_to_physical(self):
987+ yield deferToDatabase(register_system_triggers)
988+ interface = yield deferToDatabase(self.create_unknown_interface)
989+ node = yield deferToDatabase(self.create_node)
990+ zone_serial = yield self.get_zone_serial_current()
991+ dv = DeferredValue()
992+ listener = self.make_listener_without_delay()
993+ listener.register(
994+ "sys_dns", lambda *args: dv.set(args))
995+ yield listener.startService()
996+ try:
997+ yield deferToDatabase(
998+ self.migrate_unknown_to_physical, interface.id, node)
999+ yield dv.get(timeout=2)
1000+ yield self.assertZoneSerialIncrement(zone_serial)
1001+ finally:
1002+ yield listener.stopService()
1003+
1004+ @wait_for_reactor
1005+ @inlineCallbacks
1006+ def test_sends_message_for_physical_to_unknown(self):
1007+ yield deferToDatabase(register_system_triggers)
1008+ interface = yield deferToDatabase(self.create_interface)
1009+ zone_serial = yield self.get_zone_serial_current()
1010+ dv = DeferredValue()
1011+ listener = self.make_listener_without_delay()
1012+ listener.register(
1013+ "sys_dns", lambda *args: dv.set(args))
1014+ yield listener.startService()
1015+ try:
1016+ yield deferToDatabase(
1017+ self.migrate_physical_to_unknown, interface.id)
1018+ yield dv.get(timeout=2)
1019+ yield self.assertZoneSerialIncrement(zone_serial)
1020+ finally:
1021+ yield listener.stopService()
1022+
1023+ @wait_for_reactor
1024+ @inlineCallbacks
1025+ def test_sends_message_for_interface_changing_to_new_node(self):
1026+ yield deferToDatabase(register_system_triggers)
1027+ interface = yield deferToDatabase(self.create_interface)
1028+ node = yield deferToDatabase(self.create_node)
1029+ zone_serial = yield self.get_zone_serial_current()
1030+ dv = DeferredValue()
1031+ listener = self.make_listener_without_delay()
1032+ listener.register(
1033+ "sys_dns", lambda *args: dv.set(args))
1034+ yield listener.startService()
1035+ try:
1036+ yield deferToDatabase(
1037+ self.update_interface, interface.id, {"node": node})
1038+ yield dv.get(timeout=2)
1039+ yield self.assertZoneSerialIncrement(zone_serial)
1040+ finally:
1041+ yield listener.stopService()
1042+
1043+
1044+class TestDNSConfigListener(
1045+ MAASTransactionServerTestCase, TransactionalHelpersMixin,
1046+ DNSHelpersMixin):
1047+ """End-to-end test for the DNS triggers code."""
1048+
1049+ @wait_for_reactor
1050+ @inlineCallbacks
1051+ def test_sends_message_for_config_upstream_dns_insert(self):
1052+ yield deferToDatabase(register_system_triggers)
1053+ zone_serial = yield self.get_zone_serial_current()
1054+ dv = DeferredValue()
1055+ listener = self.make_listener_without_delay()
1056+ listener.register(
1057+ "sys_dns", lambda *args: dv.set(args))
1058+ yield listener.startService()
1059+ try:
1060+ yield deferToDatabase(
1061+ Config.objects.set_config,
1062+ "upstream_dns", factory.make_ip_address())
1063+ yield dv.get(timeout=2)
1064+ yield self.assertZoneSerialIncrement(zone_serial)
1065+ finally:
1066+ yield listener.stopService()
1067+
1068+ @wait_for_reactor
1069+ @inlineCallbacks
1070+ def test_sends_message_for_config_default_dns_ttl_insert(self):
1071+ yield deferToDatabase(register_system_triggers)
1072+ zone_serial = yield self.get_zone_serial_current()
1073+ dv = DeferredValue()
1074+ listener = self.make_listener_without_delay()
1075+ listener.register(
1076+ "sys_dns", lambda *args: dv.set(args))
1077+ yield listener.startService()
1078+ try:
1079+ yield deferToDatabase(
1080+ Config.objects.set_config,
1081+ "default_dns_ttl", random.randint(10, 1000))
1082+ yield dv.get(timeout=2)
1083+ yield self.assertZoneSerialIncrement(zone_serial)
1084+ finally:
1085+ yield listener.stopService()
1086+
1087+ @wait_for_reactor
1088+ @inlineCallbacks
1089+ def test_sends_message_for_config_windows_kms_host_insert(self):
1090+ yield deferToDatabase(register_system_triggers)
1091+ zone_serial = yield self.get_zone_serial_current()
1092+ dv = DeferredValue()
1093+ listener = self.make_listener_without_delay()
1094+ listener.register(
1095+ "sys_dns", lambda *args: dv.set(args))
1096+ yield listener.startService()
1097+ try:
1098+ yield deferToDatabase(
1099+ Config.objects.set_config,
1100+ "windows_kms_host", factory.make_name("kms"))
1101+ yield dv.get(timeout=2)
1102+ yield self.assertZoneSerialIncrement(zone_serial)
1103+ finally:
1104+ yield listener.stopService()
1105+
1106+ @wait_for_reactor
1107+ @inlineCallbacks
1108+ def test_sends_message_for_config_upstream_dns_update(self):
1109+ yield deferToDatabase(register_system_triggers)
1110+ yield deferToDatabase(
1111+ Config.objects.set_config,
1112+ "upstream_dns", factory.make_ip_address())
1113+ zone_serial = yield self.get_zone_serial_current()
1114+ dv = DeferredValue()
1115+ listener = self.make_listener_without_delay()
1116+ listener.register(
1117+ "sys_dns", lambda *args: dv.set(args))
1118+ yield listener.startService()
1119+ try:
1120+ yield deferToDatabase(
1121+ Config.objects.set_config,
1122+ "upstream_dns", factory.make_ip_address())
1123+ yield dv.get(timeout=2)
1124+ yield self.assertZoneSerialIncrement(zone_serial)
1125+ finally:
1126+ yield listener.stopService()
1127+
1128+ @wait_for_reactor
1129+ @inlineCallbacks
1130+ def test_sends_message_for_config_default_dns_ttl_update(self):
1131+ yield deferToDatabase(register_system_triggers)
1132+ yield deferToDatabase(
1133+ Config.objects.set_config,
1134+ "default_dns_ttl", random.randint(10, 1000))
1135+ zone_serial = yield self.get_zone_serial_current()
1136+ dv = DeferredValue()
1137+ listener = self.make_listener_without_delay()
1138+ listener.register(
1139+ "sys_dns", lambda *args: dv.set(args))
1140+ yield listener.startService()
1141+ try:
1142+ yield deferToDatabase(
1143+ Config.objects.set_config,
1144+ "default_dns_ttl", random.randint(10, 1000))
1145+ yield dv.get(timeout=2)
1146+ yield self.assertZoneSerialIncrement(zone_serial)
1147+ finally:
1148+ yield listener.stopService()
1149+
1150+ @wait_for_reactor
1151+ @inlineCallbacks
1152+ def test_sends_message_for_config_windows_kms_host_update(self):
1153+ yield deferToDatabase(register_system_triggers)
1154+ yield deferToDatabase(
1155+ Config.objects.set_config,
1156+ "windows_kms_host", factory.make_name("kms"))
1157+ zone_serial = yield self.get_zone_serial_current()
1158+ dv = DeferredValue()
1159+ listener = self.make_listener_without_delay()
1160+ listener.register(
1161+ "sys_dns", lambda *args: dv.set(args))
1162+ yield listener.startService()
1163+ try:
1164+ yield deferToDatabase(
1165+ Config.objects.set_config,
1166+ "windows_kms_host", factory.make_name("kms"))
1167+ yield dv.get(timeout=2)
1168+ yield self.assertZoneSerialIncrement(zone_serial)
1169+ finally:
1170+ yield listener.stopService()