← Back to team overview

sts-sponsors team mailing list archive

[Merge] ~cgrabowski/maas:backport_fix_dynamic_updates_for_glue_zones_to_3.3 into maas:3.3

 

Christian Grabowski has proposed merging ~cgrabowski/maas:backport_fix_dynamic_updates_for_glue_zones_to_3.3 into maas:3.3.

Commit message:
fix adding dynamic updates for reverse glue zones
(cherry picked from commit 654d7968ef00118b3ed8dda9769ec1f578e81339)

Requested reviews:
  MAAS Maintainers (maas-maintainers)

For more details, see:
https://code.launchpad.net/~cgrabowski/maas/+git/maas/+merge/434708
-- 
Your team MAAS Committers is subscribed to branch maas:3.3.
diff --git a/src/maasserver/dns/tests/test_zonegenerator.py b/src/maasserver/dns/tests/test_zonegenerator.py
index 5a3aee1..598074f 100644
--- a/src/maasserver/dns/tests/test_zonegenerator.py
+++ b/src/maasserver/dns/tests/test_zonegenerator.py
@@ -48,6 +48,7 @@ from maasserver.utils.orm import transactional
 from maastesting.factory import factory as maastesting_factory
 from maastesting.fakemethod import FakeMethod
 from maastesting.matchers import MockAnyCall, MockCalledOnceWith, MockNotCalled
+from provisioningserver.dns.config import DynamicDNSUpdate
 from provisioningserver.dns.zoneconfig import (
     DNSForwardZoneConfig,
     DNSReverseZoneConfig,
@@ -510,6 +511,49 @@ class TestZoneGenerator(MAASServerTestCase):
         }
         self.assertEqual(expected_map, zones[0]._other_mapping)
 
+    def test_glue_receives_correct_dynamic_updates(self):
+        domain = factory.make_Domain()
+        subnet = factory.make_Subnet(cidr=str(IPNetwork("10/29").cidr))
+        sip = factory.make_StaticIPAddress(subnet=subnet)
+        factory.make_Node_with_Interface_on_Subnet(
+            subnet=subnet, vlan=subnet.vlan, fabric=subnet.vlan.fabric
+        )
+        update_rec = factory.make_DNSResource(
+            name=factory.make_name(), domain=domain, ip_addresses=[sip]
+        )
+        updates = [
+            DynamicDNSUpdate(
+                operation="INSERT",
+                name=update_rec.name,
+                zone=domain.name,
+                rectype="A",
+                answer=sip.ip,
+            )
+        ]
+        zones = ZoneGenerator(
+            domain,
+            subnet,
+            serial=random.randint(0, 65535),
+            dynamic_updates=updates,
+        ).as_list()
+        self.assertCountEqual(zones[0]._dynamic_updates, updates)
+        self.assertCountEqual(
+            zones[1]._dynamic_updates,
+            [
+                DynamicDNSUpdate.as_reverse_record_update(
+                    updates[0], str(IPNetwork("10/29"))
+                )
+            ],
+        )
+        self.assertCountEqual(
+            zones[2]._dynamic_updates,
+            [
+                DynamicDNSUpdate.as_reverse_record_update(
+                    updates[0], str(IPNetwork("10/24"))
+                )
+            ],
+        )
+
     def test_parent_of_default_domain_gets_glue(self):
         default_domain = Domain.objects.get_default_domain()
         default_domain.name = "maas.example.com"
diff --git a/src/maasserver/dns/zonegenerator.py b/src/maasserver/dns/zonegenerator.py
index ef31cfa..658147f 100644
--- a/src/maasserver/dns/zonegenerator.py
+++ b/src/maasserver/dns/zonegenerator.py
@@ -452,7 +452,9 @@ class ZoneGenerator:
                 glue = set()
 
             domain_updates = [
-                DynamicDNSUpdate.as_reverse_record_update(update, subnet)
+                DynamicDNSUpdate.as_reverse_record_update(
+                    update, str(subnet.cidr)
+                )
                 for update in dynamic_updates
                 if update.answer
                 and update.answer_is_ip
@@ -476,6 +478,28 @@ class ZoneGenerator:
             )
         # Now provide any remaining rfc2317 glue networks.
         for network, ranges in rfc2317_glue.items():
+            exclude_set = {
+                IPNetwork(s.cidr)
+                for s in subnets
+                if network in IPNetwork(s.cidr)
+            }
+            domain_updates = []
+            for update in dynamic_updates:
+                glue_update = True
+                for exclude_net in exclude_set:
+                    if (
+                        update.answer
+                        and update.answer_is_ip
+                        and IPAddress(update.answer) in exclude_net
+                    ):
+                        glue_update = False
+                        break
+                if glue_update:
+                    domain_updates.append(
+                        DynamicDNSUpdate.as_reverse_record_update(
+                            update, str(network)
+                        )
+                    )
             yield DNSReverseZoneConfig(
                 ns_host_name,
                 serial=serial,
@@ -483,11 +507,7 @@ class ZoneGenerator:
                 network=network,
                 ns_host_name=ns_host_name,
                 rfc2317_ranges=ranges,
-                exclude={
-                    IPNetwork(s.cidr)
-                    for s in subnets
-                    if network in IPNetwork(s.cidr)
-                },
+                exclude=exclude_set,
                 dynamic_updates=domain_updates,
                 force_config_write=force_config_write,
             )
diff --git a/src/provisioningserver/dns/tests/test_zoneconfig.py b/src/provisioningserver/dns/tests/test_zoneconfig.py
index 948d219..24e18e1 100644
--- a/src/provisioningserver/dns/tests/test_zoneconfig.py
+++ b/src/provisioningserver/dns/tests/test_zoneconfig.py
@@ -967,6 +967,93 @@ class TestDNSReverseZoneConfig(MAASTestCase):
             stdin=expected_stdin.encode("ascii"),
         )
 
+    def test_glue_network_zone_contains_appropriate_dynamic_updates(self):
+        patch_zone_file_config_path(self)
+        domain = factory.make_string()
+        network = IPNetwork("10.0.0.0/26")
+        glue_network = IPNetwork("10.0.0.0/24")
+        ip1 = factory.pick_ip_in_network(network)
+        ip2 = factory.pick_ip_in_network(network)
+        hostname1 = f"{factory.make_string()}.{domain}"
+        hostname2 = f"{factory.make_string()}.{domain}"
+        fwd_updates = [
+            DynamicDNSUpdate(
+                operation="INSERT",
+                zone=domain,
+                name=hostname1,
+                rectype="A",
+                answer=ip1,
+            ),
+            DynamicDNSUpdate(
+                operation="INSERT",
+                zone=domain,
+                name=hostname2,
+                rectype="A",
+                answer=ip2,
+            ),
+        ]
+        rev_updates = [
+            DynamicDNSUpdate.as_reverse_record_update(update, str(network))
+            for update in fwd_updates
+        ]
+        zone = DNSReverseZoneConfig(
+            domain,
+            serial=random.randint(1, 100),
+            network=network,
+            dynamic_updates=rev_updates,
+        )
+        glue_rev_updates = [
+            DynamicDNSUpdate.as_reverse_record_update(
+                update, str(glue_network)
+            )
+            for update in fwd_updates
+        ]
+        glue_zone = DNSReverseZoneConfig(
+            domain,
+            serial=random.randint(1, 100),
+            network=glue_network,
+            dynamic_updates=glue_rev_updates,
+        )
+        expected_stdin = "\n".join(
+            [
+                "server localhost",
+                "zone 0-26.0.0.10.in-addr.arpa",
+                f"update add {IPAddress(ip1).reverse_dns} {zone.default_ttl} PTR {hostname1}",
+                f"update add {IPAddress(ip2).reverse_dns} {zone.default_ttl} PTR {hostname2}",
+                f"update add 0-26.0.0.10.in-addr.arpa {zone.default_ttl} SOA 0-26.0.0.10.in-addr.arpa. nobody.example.com. {zone.serial} 600 1800 604800 {zone.default_ttl}",
+                "send\n",
+            ]
+        )
+        glue_expected_stdin = "\n".join(
+            [
+                "server localhost",
+                "zone 0.0.10.in-addr.arpa",
+                f"update add {IPAddress(ip1).reverse_dns} {zone.default_ttl} PTR {hostname1}",
+                f"update add {IPAddress(ip2).reverse_dns} {zone.default_ttl} PTR {hostname2}",
+                f"update add 0.0.10.in-addr.arpa {glue_zone.default_ttl} SOA 0.0.10.in-addr.arpa. nobody.example.com. {glue_zone.serial} 600 1800 604800 {glue_zone.default_ttl}",
+                "send\n",
+            ]
+        )
+        run_command = self.patch(actions, "run_command")
+        glue_zone.write_config()
+        glue_zone.write_config()
+        run_command.assert_called_with(
+            "nsupdate",
+            "-k",
+            get_nsupdate_key_path(),
+            "-v",
+            stdin=glue_expected_stdin.encode("ascii"),
+        )
+        zone.write_config()
+        zone.write_config()
+        run_command.assert_called_with(
+            "nsupdate",
+            "-k",
+            get_nsupdate_key_path(),
+            "-v",
+            stdin=expected_stdin.encode("ascii"),
+        )
+
 
 class TestDNSReverseZoneConfig_GetGenerateDirectives(MAASTestCase):
     """Tests for `DNSReverseZoneConfig.get_GENERATE_directives()`."""
diff --git a/src/provisioningserver/dns/zoneconfig.py b/src/provisioningserver/dns/zoneconfig.py
index eed539a..3c6e383 100644
--- a/src/provisioningserver/dns/zoneconfig.py
+++ b/src/provisioningserver/dns/zoneconfig.py
@@ -177,7 +177,8 @@ class DomainConfigBase:
             [
                 update
                 for update in self._dynamic_updates
-                if update.zone == zone_info.zone_name or update.subnet
+                if update.zone == zone_info.zone_name
+                or IPNetwork(update.subnet) == zone_info.subnetwork
             ],
             serial=self.serial,
             ttl=self.default_ttl,

References