diff --git a/octodns/zone.py b/octodns/zone.py index c35e94c..ba527a2 100644 --- a/octodns/zone.py +++ b/octodns/zone.py @@ -75,6 +75,28 @@ class Zone(object): # it has utf8 chars return self._utf8_name_re.sub('', fqdn) + def owns(self, _type, fqdn): + if fqdn[-1] != '.': + fqdn = f'{fqdn}.' + + # if we don't end with the zone's name we aren't owned by it + if not fqdn.endswith(self.name): + return False + + hostname = self.hostname_from_fqdn(fqdn) + if hostname in self.sub_zones: + # if our hostname matches a sub-zone exactly we have to be a NS + # record + return _type == 'NS' + + for sub_zone in self.sub_zones: + if hostname.endswith(f'.{sub_zone}'): + # this belongs under a sub-zone + return False + + # otherwise we own it + return True + def add_record(self, record, replace=False, lenient=False): if self._origin: self.hydrate() diff --git a/tests/test_octodns_zone.py b/tests/test_octodns_zone.py index 0ee01b0..b3f76e2 100644 --- a/tests/test_octodns_zone.py +++ b/tests/test_octodns_zone.py @@ -191,6 +191,25 @@ class TestZone(TestCase): Zone('space not allowed.', []) self.assertTrue('whitespace not allowed' in str(ctx.exception)) + def test_owns(self): + zone = Zone('unit.tests.', set(['sub'])) + + self.assertTrue(zone.owns('A', 'unit.tests')) + self.assertTrue(zone.owns('A', 'unit.tests.')) + self.assertTrue(zone.owns('A', 'www.unit.tests.')) + self.assertTrue(zone.owns('A', 'www.unit.tests.')) + # we do own our direct sub's delegation NS records + self.assertTrue(zone.owns('NS', 'sub.unit.tests.')) + + # we don't own the root of our sub + self.assertFalse(zone.owns('A', 'sub.unit.tests.')) + + # of anything under it + self.assertFalse(zone.owns('A', 'www.sub.unit.tests.')) + + # including subsequent delegatoin NS records + self.assertFalse(zone.owns('NS', 'below.sub.unit.tests.')) + def test_sub_zones(self): # NS for exactly the sub is allowed zone = Zone('unit.tests.', set(['sub', 'barred']))