sts-sponsors team mailing list archive
-
sts-sponsors team
-
Mailing list archive
-
Message #04097
[Merge] ~cgrabowski/maas:backport_fix_node_dns_generation_to_3.3 into maas:3.3
Christian Grabowski has proposed merging ~cgrabowski/maas:backport_fix_node_dns_generation_to_3.3 into maas:3.3.
Commit message:
add trigger when existing static ip updates
add DELETE-IFACE-IP
add triggers for interface to ip dynamic DNS updates
(cherry picked from commit 147cc75221abc14a66bb8737057663065b5f6173)
Requested reviews:
Christian Grabowski (cgrabowski)
For more details, see:
https://code.launchpad.net/~cgrabowski/maas/+git/maas/+merge/434580
--
Your team MAAS Committers is subscribed to branch maas:3.3.
diff --git a/src/maasserver/dns/config.py b/src/maasserver/dns/config.py
index c484570..a0390c0 100644
--- a/src/maasserver/dns/config.py
+++ b/src/maasserver/dns/config.py
@@ -21,6 +21,7 @@ from maasserver.models.dnsdata import DNSData
from maasserver.models.dnspublication import DNSPublication
from maasserver.models.dnsresource import DNSResource
from maasserver.models.domain import Domain
+from maasserver.models.interface import Interface
from maasserver.models.node import RackController
from maasserver.models.subnet import Subnet
from provisioningserver.dns.actions import (
@@ -348,7 +349,7 @@ def process_dns_update_notify(message):
case _:
# special case where we know an IP has been deleted but, we can't fetch the value
# and the rrecord may still have other answers
- if op == "DELETE-IP":
+ if op == "DELETE-IP" or op == "DELETE-IFACE-IP":
updates.append(
DynamicDNSUpdate.create_from_trigger(
operation="DELETE",
@@ -366,23 +367,42 @@ def process_dns_update_notify(message):
rectype="AAAA",
)
)
- resource = DNSResource.objects.get(
- name=update_list[2], domain__name=zone
- )
+
+ ttl = None
+ ip_addresses = []
+ if op == "DELETE-IP":
+ resource = DNSResource.objects.get(
+ name=update_list[2], domain__name=zone
+ )
+ ttl = (
+ int(resource.address_ttl)
+ if resource.address_ttl
+ else None
+ )
+ ip_addresses = list(
+ resource.ip_addresses.exclude(ip__isnull=True)
+ )
+ else:
+ iface_id = int(update_list[-1])
+ iface = Interface.objects.get(id=iface_id)
+ default_domain = Domain.objects.get_default_domain()
+ ttl = (
+ int(default_domain.ttl) if default_domain.ttl else None
+ )
+ ip_addresses = list(
+ iface.ip_addresses.exclude(ip__isnull=True)
+ )
updates += [
DynamicDNSUpdate.create_from_trigger(
operation="INSERT",
zone=zone,
name=name,
rectype=rectype,
- ttl=int(resource.address_ttl)
- if resource.address_ttl
- else None,
+ ttl=ttl,
answer=ip.ip,
)
- for ip in resource.ip_addresses.all()
+ for ip in ip_addresses
]
-
elif len(update_list) > 4: # has an answer
updates.append(
DynamicDNSUpdate.create_from_trigger(
diff --git a/src/maasserver/dns/tests/test_config.py b/src/maasserver/dns/tests/test_config.py
index 9a2835d..0a96814 100644
--- a/src/maasserver/dns/tests/test_config.py
+++ b/src/maasserver/dns/tests/test_config.py
@@ -873,7 +873,10 @@ class TestProcessDNSUpdateNotify(MAASServerTestCase):
domain = factory.make_Domain()
resource = factory.make_DNSResource(domain=domain)
ip = resource.ip_addresses.first().ip
- ip2 = factory.make_StaticIPAddress()
+ subnet = factory.make_Subnet()
+ ip2 = factory.make_StaticIPAddress(
+ subnet=subnet, ip=subnet.get_next_ip_for_allocation()[0]
+ )
resource.ip_addresses.add(ip2)
message = f"DELETE-IP {domain.name} {resource.name} A {resource.address_ttl if resource.address_ttl else 60} {ip}"
resource.ip_addresses.first().delete()
@@ -902,3 +905,37 @@ class TestProcessDNSUpdateNotify(MAASServerTestCase):
],
result,
)
+
+ def test_delete_iface_ip(self):
+ domain = factory.make_Domain()
+ node = factory.make_Node_with_Interface_on_Subnet()
+ iface = node.current_config.interface_set.first()
+ ip1 = iface.ip_addresses.first()
+ ip2 = factory.make_StaticIPAddress(interface=iface)
+ ip1.delete()
+ message = f"DELETE-IFACE-IP {domain.name} {node.hostname} A {domain.ttl if domain.ttl else 60} {iface.id}"
+ result, _ = process_dns_update_notify(message)
+ self.assertCountEqual(
+ [
+ DynamicDNSUpdate(
+ operation="DELETE",
+ zone=domain.name,
+ name=f"{node.hostname}.{domain.name}",
+ rectype="A",
+ ),
+ DynamicDNSUpdate(
+ operation="DELETE",
+ zone=domain.name,
+ name=f"{node.hostname}.{domain.name}",
+ rectype="AAAA",
+ ),
+ DynamicDNSUpdate(
+ operation="INSERT",
+ zone=domain.name,
+ name=f"{node.hostname}.{domain.name}",
+ rectype="A" if IPAddress(ip2.ip).version == 4 else "AAAA",
+ answer=ip2.ip,
+ ),
+ ],
+ result,
+ )
diff --git a/src/maasserver/triggers/system.py b/src/maasserver/triggers/system.py
index a18fe8a..3f7f328 100644
--- a/src/maasserver/triggers/system.py
+++ b/src/maasserver/triggers/system.py
@@ -2054,6 +2054,124 @@ def render_dns_dynamic_update_subnet_procedure(op):
)
+def render_dns_dynamic_update_interface_static_ip_address(op):
+ return dedent(
+ f"""\
+ CREATE OR REPLACE FUNCTION sys_dns_updates_interface_ip_{op}()
+ RETURNS trigger as $$
+ DECLARE
+ current_hostname text;
+ domain text;
+ iface_name text;
+ ip_addr text;
+ address_ttl int;
+ BEGIN
+ ASSERT TG_WHEN = 'AFTER', 'May only run as an AFTER trigger';
+ ASSERT TG_LEVEL <> 'STATEMENT', 'Should not be used as a STATEMENT level trigger', TG_NAME;
+ IF (TG_OP = 'INSERT' AND TG_LEVEL = 'ROW') THEN
+ SELECT iface.name, node.hostname, domain_tbl.name, COALESCE(domain_tbl.ttl, 0) INTO iface_name, current_hostname, domain, address_ttl
+ FROM maasserver_interface AS iface
+ JOIN maasserver_node AS node ON iface.node_config_id = node.current_config_id
+ JOIN maasserver_domain AS domain_tbl ON domain_tbl.id=node.domain_id WHERE iface.id=NEW.interface_id;
+ SELECT host(ip) INTO ip_addr FROM maasserver_staticipaddress WHERE id=NEW.staticipaddress_id;
+ PERFORM pg_notify('sys_dns_updates', 'INSERT ' || domain || ' ' || current_hostname || ' A ' || address_ttl || ' ' || ip_addr);
+ PERFORM pg_notify('sys_dns_updates', 'INSERT ' || domain || ' ' || iface_name || '.' || current_hostname || ' A ' || address_ttl || ' ' || ip_addr);
+ ELSIF (TG_OP = 'DELETE' AND TG_LEVEL = 'ROW') THEN
+ IF EXISTS(SELECT id FROM maasserver_interface WHERE id=OLD.interface_id) THEN
+ SELECT iface.name, node.hostname, domain_tbl.name, COALESCE(domain_tbl.ttl, 0) INTO iface_name, current_hostname, domain, address_ttl
+ FROM maasserver_interface AS iface
+ JOIN maasserver_node AS node ON iface.node_config_id = node.current_config_id
+ JOIN maasserver_domain AS domain_tbl ON domain_tbl.id=node.domain_id WHERE iface.id=OLD.interface_id;
+ IF EXISTS(SELECT id FROM maasserver_staticipaddress WHERE id=OLD.staticipaddress_id) THEN
+ SELECT host(ip) INTO ip_addr FROM maasserver_staticipaddress WHERE id=OLD.staticipaddress_id;
+ PERFORM pg_notify('sys_dns_updates', 'DELETE ' || domain || ' ' || current_hostname || ' A ' || ip_addr);
+ PERFORM pg_notify('sys_dns_updates', 'DELETE ' || domain || ' ' || iface_name || '.' || current_hostname || ' A ' || ip_addr);
+ ELSE
+ PERFORM pg_notify('sys_dns_updates', 'DELETE-IFACE-IP ' || domain || ' ' || current_hostname || ' A ' || OLD.interface_id);
+ PERFORM pg_notify('sys_dns_updates', 'DELETE-IFACE-IP ' || domain || ' ' || current_hostname || ' AAAA ' || OLD.interface_id);
+ END IF;
+ END IF;
+ END IF;
+ RETURN NULL;
+ END;
+ $$ LANGUAGE plpgsql;
+ """
+ )
+
+
+dns_dynamic_update_static_ip_address_update = dedent(
+ """\
+ CREATE OR REPLACE FUNCTION sys_dns_updates_ip_update()
+ RETURNS trigger as $$
+ DECLARE
+ current_hostname text;
+ domain text;
+ iface_name text;
+ address_ttl int;
+ current_interface_id bigint;
+ BEGIN
+ IF NEW IS DISTINCT FROM OLD THEN
+ IF EXISTS(SELECT id FROM maasserver_interface_ip_addresses WHERE staticipaddress_id=NEW.id) THEN
+ SELECT interface_id INTO current_interface_id FROM maasserver_interface_ip_addresses WHERE staticipaddress_id=NEW.id;
+ SELECT iface.name, node.hostname, domain_tbl.name, COALESCE(domain_tbl.ttl, 0) INTO iface_name, current_hostname, domain, address_ttl
+ FROM maasserver_interface AS iface
+ JOIN maasserver_node AS node ON iface.node_config_id = node.current_config_id
+ JOIN maasserver_domain AS domain_tbl ON domain_tbl.id=node.domain_id WHERE iface.id=current_interface_id;
+ IF OLD.ip IS NOT NULL THEN
+ PERFORM pg_notify('sys_dns_updates', 'DELETE ' || domain || ' ' || current_hostname || ' A ' || host(OLD.ip));
+ PERFORM pg_notify('sys_dns_updates', 'DELETE ' || domain || ' ' || iface_name || '.' || current_hostname || ' A ' || host(OLD.ip));
+ END IF;
+ PERFORM pg_notify('sys_dns_updates', 'INSERT ' || domain || ' ' || current_hostname || ' A ' || address_ttl || ' ' || host(NEW.ip));
+ PERFORM pg_notify('sys_dns_updates', 'INSERT ' || domain || ' ' || iface_name || '.' || current_hostname || ' A ' || address_ttl || ' ' || host(NEW.ip));
+ END IF;
+ END IF;
+ RETURN NULL;
+ END;
+ $$ LANGUAGE plpgsql;
+ """
+)
+
+dns_dynamic_update_node_delete = dedent(
+ """\
+ CREATE OR REPLACE FUNCTION sys_dns_updates_maasserver_node_delete()
+ RETURNS trigger as $$
+ DECLARE
+ hostname text;
+ domain text;
+ address_ttl int;
+ BEGIN
+ SELECT name, COALESCE(ttl, 0) INTO domain, address_ttl FROM maasserver_domain WHERE id=OLD.domain_id;
+ PERFORM pg_notify('sys_dns_updates', 'DELETE ' || domain || ' ' || OLD.hostname || ' A');
+ RETURN NULL;
+ END;
+ $$ LANGUAGE plpgsql;
+ """
+)
+
+
+dns_dynamic_update_interface_delete = dedent(
+ """\
+ CREATE OR REPLACE FUNCTION sys_dns_updates_maasserver_interface_delete()
+ RETURNS trigger as $$
+ DECLARE
+ current_hostname text;
+ current_domain_id bigint;
+ domain text;
+ current_node_id bigint;
+ BEGIN
+ IF EXISTS(SELECT id FROM maasserver_nodeconfig WHERE id=OLD.node_config_id) THEN
+ SELECT node_id INTO current_node_id FROM maasserver_nodeconfig WHERE id=OLD.node_config_id;
+ SELECT hostname, domain_id INTO current_hostname, current_domain_id FROM maasserver_node WHERE id=current_node_id;
+ SELECT name INTO domain FROM maasserver_domain WHERE id=current_domain_id;
+ PERFORM pg_notify('sys_dns_updates', 'DELETE ' || domain || ' ' || OLD.name || '.' || current_hostname || ' A');
+ END IF;
+ RETURN NULL;
+ END;
+ $$ LANGUAGE plpgsql;
+ """
+)
+
+
def render_sys_proxy_procedure(proc_name, on_delete=False):
"""Render a database procedure with name `proc_name` that notifies that a
proxy update is needed.
@@ -2403,3 +2521,37 @@ def register_system_triggers():
"sys_dns_updates_maasserver_subnet_delete",
"delete",
)
+ register_procedure(
+ render_dns_dynamic_update_interface_static_ip_address("insert")
+ )
+ register_trigger(
+ "maasserver_interface_ip_addresses",
+ "sys_dns_updates_interface_ip_insert",
+ "insert",
+ )
+ register_procedure(
+ render_dns_dynamic_update_interface_static_ip_address("delete")
+ )
+ register_trigger(
+ "maasserver_interface_ip_addresses",
+ "sys_dns_updates_interface_ip_delete",
+ "delete",
+ )
+ register_procedure(dns_dynamic_update_static_ip_address_update)
+ register_trigger(
+ "maasserver_staticipaddress",
+ "sys_dns_updates_ip_update",
+ "update",
+ )
+ register_procedure(dns_dynamic_update_node_delete)
+ register_trigger(
+ "maasserver_node",
+ "sys_dns_updates_maasserver_node_delete",
+ "delete",
+ )
+ register_procedure(dns_dynamic_update_interface_delete)
+ register_trigger(
+ "maasserver_interface",
+ "sys_dns_updates_maasserver_interface_delete",
+ "delete",
+ )
diff --git a/src/maasserver/triggers/tests/test_init.py b/src/maasserver/triggers/tests/test_init.py
index e4fb3ed..34395f1 100644
--- a/src/maasserver/triggers/tests/test_init.py
+++ b/src/maasserver/triggers/tests/test_init.py
@@ -91,14 +91,18 @@ class TestTriggersUsed(MAASServerTestCase):
"domain_sys_dns_updates_maasserver_domain_update",
"interface_ip_addresses_sys_dns_nic_ip_link",
"interface_ip_addresses_sys_dns_nic_ip_unlink",
+ "interface_ip_addresses_sys_dns_updates_interface_ip_insert",
+ "interface_ip_addresses_sys_dns_updates_interface_ip_delete",
"interface_sys_dhcp_interface_update",
"interface_sys_dns_interface_update",
+ "interface_sys_dns_updates_maasserver_interface_delete",
"iprange_sys_dhcp_iprange_delete",
"iprange_sys_dhcp_iprange_insert",
"iprange_sys_dhcp_iprange_update",
"node_sys_dhcp_node_update",
"node_sys_dns_node_delete",
"node_sys_dns_node_update",
+ "node_sys_dns_updates_maasserver_node_delete",
"rbacsync_sys_rbac_sync",
"regionrackrpcconnection_sys_core_rpc_delete",
"regionrackrpcconnection_sys_core_rpc_insert",
@@ -109,6 +113,7 @@ class TestTriggersUsed(MAASServerTestCase):
"staticipaddress_sys_dhcp_staticipaddress_insert",
"staticipaddress_sys_dhcp_staticipaddress_update",
"staticipaddress_sys_dns_staticipaddress_update",
+ "staticipaddress_sys_dns_updates_ip_update",
"subnet_sys_dns_updates_maasserver_subnet_delete",
"subnet_sys_dns_updates_maasserver_subnet_insert",
"subnet_sys_dns_updates_maasserver_subnet_update",
diff --git a/src/maasserver/triggers/tests/test_system.py b/src/maasserver/triggers/tests/test_system.py
index d5222b4..4337984 100644
--- a/src/maasserver/triggers/tests/test_system.py
+++ b/src/maasserver/triggers/tests/test_system.py
@@ -7,6 +7,8 @@ from contextlib import closing
from django.db import connection
from twisted.internet.defer import inlineCallbacks
+from maasserver.enum import NODE_STATUS
+from maasserver.models import Domain
from maasserver.models.dnspublication import zone_serial
from maasserver.testing.factory import factory
from maasserver.testing.testcase import (
@@ -367,3 +369,272 @@ class TestSysDNSUpdates(
finally:
self.stop_reading()
yield self.postgres_listener_service.stopService()
+
+ @wait_for_reactor
+ @inlineCallbacks
+ def test_dns_dynamic_update_interface_static_ip_address_insert(self):
+ listener = self.make_listener_without_delay()
+ yield self.set_service(listener)
+ yield deferToDatabase(
+ self.register_trigger,
+ "maasserver_interface_ip_addresses",
+ "sys_dns_updates",
+ ops=("insert",),
+ trigger="sys_dns_updates_interface_ip_insert",
+ )
+ vlan = yield deferToDatabase(self.create_vlan)
+ subnet = yield deferToDatabase(
+ self.create_subnet, params={"vlan": vlan}
+ )
+ self.start_reading()
+ try:
+ node = yield deferToDatabase(
+ self.create_node_with_interface,
+ params={"subnet": subnet, "status": NODE_STATUS.DEPLOYED},
+ )
+ domain = yield deferToDatabase(Domain.objects.get_default_domain)
+ expected_iface = yield deferToDatabase(
+ lambda: node.current_config.interface_set.first()
+ )
+ expected_ip = yield deferToDatabase(
+ lambda: self.create_staticipaddress(
+ params={
+ "ip": subnet.get_next_ip_for_allocation()[0],
+ "interface": expected_iface,
+ "subnet": subnet,
+ }
+ )
+ )
+ msg1 = yield self.get_notify("sys_dns_updates")
+ self.assertEqual(
+ msg1,
+ f"INSERT {domain.name} {node.hostname} A 0 {expected_ip.ip}",
+ )
+ msg2 = yield self.get_notify("sys_dns_updates")
+ self.assertEqual(
+ msg2,
+ f"INSERT {domain.name} {expected_iface.name}.{node.hostname} A 0 {expected_ip.ip}",
+ )
+ finally:
+ self.stop_reading()
+ yield self.postgres_listener_service.stopService()
+
+ @wait_for_reactor
+ @inlineCallbacks
+ def test_dns_dynamic_update_interface_static_ip_address_insert_with_non_default_domain(
+ self,
+ ):
+ listener = self.make_listener_without_delay()
+ yield self.set_service(listener)
+ yield deferToDatabase(
+ self.register_trigger,
+ "maasserver_interface_ip_addresses",
+ "sys_dns_updates",
+ ops=("insert",),
+ trigger="sys_dns_updates_interface_ip_insert",
+ )
+ vlan = yield deferToDatabase(self.create_vlan)
+ subnet = yield deferToDatabase(
+ self.create_subnet, params={"vlan": vlan}
+ )
+ domain = yield deferToDatabase(self.create_domain)
+ self.start_reading()
+ try:
+ node = yield deferToDatabase(
+ self.create_node_with_interface,
+ params={
+ "subnet": subnet,
+ "status": NODE_STATUS.DEPLOYED,
+ "domain": domain,
+ },
+ )
+ expected_iface = yield deferToDatabase(
+ lambda: node.current_config.interface_set.first()
+ )
+ expected_ip = yield deferToDatabase(
+ lambda: self.create_staticipaddress(
+ params={
+ "ip": subnet.get_next_ip_for_allocation()[0],
+ "interface": expected_iface,
+ "subnet": subnet,
+ }
+ )
+ )
+ msg1 = yield self.get_notify("sys_dns_updates")
+ self.assertEqual(
+ msg1,
+ f"INSERT {domain.name} {node.hostname} A 0 {expected_ip.ip}",
+ )
+ msg2 = yield self.get_notify("sys_dns_updates")
+ self.assertEqual(
+ msg2,
+ f"INSERT {domain.name} {expected_iface.name}.{node.hostname} A 0 {expected_ip.ip}",
+ )
+ finally:
+ self.stop_reading()
+ yield self.postgres_listener_service.stopService()
+
+ @wait_for_reactor
+ @inlineCallbacks
+ def test_dns_dynamic_update_interface_static_ip_address_delete(self):
+ listener = self.make_listener_without_delay()
+ yield self.set_service(listener)
+ yield deferToDatabase(
+ self.register_trigger,
+ "maasserver_interface_ip_addresses",
+ "sys_dns_updates",
+ ops=("delete",),
+ trigger="sys_dns_updates_interface_ip_delete",
+ )
+ vlan = yield deferToDatabase(self.create_vlan)
+ subnet = yield deferToDatabase(
+ self.create_subnet, params={"vlan": vlan}
+ )
+ node = yield deferToDatabase(
+ self.create_node_with_interface,
+ params={"subnet": subnet, "status": NODE_STATUS.DEPLOYED},
+ )
+ domain = yield deferToDatabase(Domain.objects.get_default_domain)
+ iface = yield deferToDatabase(
+ lambda: node.current_config.interface_set.first()
+ )
+ ip1 = yield deferToDatabase(
+ lambda: self.create_staticipaddress(
+ params={
+ "ip": subnet.get_next_ip_for_allocation()[0],
+ "interface": iface,
+ "subnet": subnet,
+ }
+ )
+ )
+ self.start_reading()
+ try:
+ yield deferToDatabase(iface.unlink_ip_address, ip1)
+ msg1 = yield self.get_notify("sys_dns_updates")
+ self.assertEqual(
+ msg1, f"DELETE {domain.name} {node.hostname} A {ip1.ip}"
+ )
+ msg2 = yield self.get_notify("sys_dns_updates")
+ self.assertEqual(
+ msg2,
+ f"DELETE {domain.name} {iface.name}.{node.hostname} A {ip1.ip}",
+ )
+ finally:
+ self.stop_reading()
+ yield self.postgres_listener_service.stopService()
+
+ @wait_for_reactor
+ @inlineCallbacks
+ def test_dns_dynamc_update_ip_update(self):
+ listener = self.make_listener_without_delay()
+ yield self.set_service(listener)
+ yield deferToDatabase(
+ self.register_trigger,
+ "maasserver_staticipaddress",
+ "sys_dns_updates",
+ ops=("update",),
+ trigger="sys_dns_updates_ip_update",
+ )
+ vlan = yield deferToDatabase(self.create_vlan)
+ subnet = yield deferToDatabase(
+ self.create_subnet, params={"vlan": vlan}
+ )
+ node = yield deferToDatabase(
+ self.create_node_with_interface,
+ params={"subnet": subnet, "status": NODE_STATUS.DEPLOYED},
+ )
+ domain = yield deferToDatabase(Domain.objects.get_default_domain)
+ iface = yield deferToDatabase(
+ lambda: node.current_config.interface_set.first()
+ )
+ ip = yield deferToDatabase(
+ lambda: self.create_staticipaddress(
+ params={
+ "ip": subnet.get_next_ip_for_allocation()[0],
+ "interface": iface,
+ "subnet": subnet,
+ }
+ )
+ )
+ old_ip = ip.ip
+
+ def _set_new_ip():
+ ip.ip = subnet.get_next_ip_for_allocation()[0]
+ ip.save()
+
+ self.start_reading()
+ try:
+ yield deferToDatabase(_set_new_ip)
+ msg1 = yield self.get_notify("sys_dns_updates")
+ self.assertEqual(
+ msg1, f"DELETE {domain.name} {node.hostname} A {old_ip}"
+ )
+ msg2 = yield self.get_notify("sys_dns_updates")
+ self.assertEqual(
+ msg2,
+ f"DELETE {domain.name} {iface.name}.{node.hostname} A {old_ip}",
+ )
+ msg3 = yield self.get_notify("sys_dns_updates")
+ self.assertEqual(
+ msg3, f"INSERT {domain.name} {node.hostname} A 0 {ip.ip}"
+ )
+ msg4 = yield self.get_notify("sys_dns_updates")
+ self.assertEqual(
+ msg4,
+ f"INSERT {domain.name} {iface.name}.{node.hostname} A 0 {ip.ip}",
+ )
+ finally:
+ self.stop_reading()
+ yield self.postgres_listener_service.stopService()
+
+ @wait_for_reactor
+ @inlineCallbacks
+ def test_dns_dynamic_update_node_delete(self):
+ listener = self.make_listener_without_delay()
+ yield self.set_service(listener)
+ yield deferToDatabase(
+ self.register_trigger,
+ "maasserver_node",
+ "sys_dns_updates",
+ ops=("delete",),
+ )
+ node = yield deferToDatabase(self.create_node)
+ domain = yield deferToDatabase(Domain.objects.get_default_domain)
+ self.start_reading()
+ try:
+ yield deferToDatabase(node.delete)
+ msg = yield self.get_notify("sys_dns_updates")
+ self.assertEqual(msg, f"DELETE {domain.name} {node.hostname} A")
+ finally:
+ self.stop_reading()
+ yield self.postgres_listener_service.stopService()
+
+ @wait_for_reactor
+ @inlineCallbacks
+ def test_dns_dynamic_update_interface_delete(self):
+ listener = self.make_listener_without_delay()
+ yield self.set_service(listener)
+ yield deferToDatabase(
+ self.register_trigger,
+ "maasserver_node",
+ "sys_dns_updates",
+ ops=("delete",),
+ )
+ subnet = yield deferToDatabase(self.create_subnet)
+ node = yield deferToDatabase(
+ self.create_node_with_interface, params={"subnet": subnet}
+ )
+ domain = yield deferToDatabase(Domain.objects.get_default_domain)
+ iface = yield deferToDatabase(
+ lambda: node.current_config.interface_set.first()
+ )
+ self.start_reading()
+ try:
+ yield deferToDatabase(iface.delete)
+ msg = yield self.get_notify("sys_dns_updates")
+ self.assertEqual(
+ msg, f"DELETE {domain.name} {iface.name}.{node.hostname} A"
+ )
+ finally:
+ self.stop_reading()
+ yield self.postgres_listener_service.stopService()
diff --git a/src/provisioningserver/dns/zoneconfig.py b/src/provisioningserver/dns/zoneconfig.py
index 13dca69..eed539a 100644
--- a/src/provisioningserver/dns/zoneconfig.py
+++ b/src/provisioningserver/dns/zoneconfig.py
@@ -7,6 +7,7 @@
from datetime import datetime
from itertools import chain
import os
+from pathlib import Path
from netaddr import IPAddress, IPNetwork, spanning_cidr
from netaddr.core import AddrFormatError
@@ -323,6 +324,7 @@ class DNSForwardZoneConfig(DomainConfigBase):
if not self.force_config_write and self.zone_file_exists(zi):
self.dynamic_update(zi)
else:
+ Path(f"{zi.target_path}.jnl").unlink(missing_ok=True)
self.requires_reload = True
self.write_zone_file(
zi.target_path,
@@ -612,6 +614,7 @@ class DNSReverseZoneConfig(DomainConfigBase):
if not self.force_config_write and self.zone_file_exists(zi):
self.dynamic_update(zi)
else:
+ Path(f"{zi.target_path}.jnl").unlink(missing_ok=True)
self.requires_reload = True
self.write_zone_file(
zi.target_path,
References