From 615bc95976ca0dba4ce8d77b06d19205d1fe7a08 Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Fri, 23 Jun 2017 09:49:25 -0700 Subject: [PATCH] CNAME cannot coexist with other records on a node --- octodns/zone.py | 18 +++++++++++++++--- tests/test_octodns_zone.py | 27 ++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/octodns/zone.py b/octodns/zone.py index 1822fec..03bc41c 100644 --- a/octodns/zone.py +++ b/octodns/zone.py @@ -19,6 +19,10 @@ class DuplicateRecordException(Exception): pass +class InvalidNodeException(Exception): + pass + + def _is_eligible(record): # Should this record be considered when computing changes # We ignore all top-level NS records @@ -59,9 +63,17 @@ class Zone(object): raise SubzoneRecordException('Record {} a managed sub-zone ' 'and not of type NS' .format(record.fqdn)) - if record in self.records: - raise DuplicateRecordException('Duplicate record {}, type {}' - .format(record.fqdn, record._type)) + for existing in self.records: + if record == existing: + raise DuplicateRecordException('Duplicate record {}, type {}' + .format(record.fqdn, + record._type)) + elif name == existing.name and (record._type == 'CNAME' or + existing._type == 'CNAME'): + raise InvalidNodeException('Invalid state, CNAME at {} ' + 'cannot coexist with other records' + .format(record.fqdn)) + self.records.add(record) def changes(self, desired, target): diff --git a/tests/test_octodns_zone.py b/tests/test_octodns_zone.py index 88bbb68..a4d7300 100644 --- a/tests/test_octodns_zone.py +++ b/tests/test_octodns_zone.py @@ -8,7 +8,8 @@ from __future__ import absolute_import, division, print_function, \ from unittest import TestCase from octodns.record import ARecord, AaaaRecord, Create, Delete, Record, Update -from octodns.zone import DuplicateRecordException, SubzoneRecordException, Zone +from octodns.zone import DuplicateRecordException, InvalidNodeException, \ + SubzoneRecordException, Zone from helpers import SimpleProvider @@ -205,3 +206,27 @@ class TestZone(TestCase): self.assertTrue(zone_missing.changes(zone_normal, provider)) self.assertFalse(zone_missing.changes(zone_ignored, provider)) + + def test_cname_coexisting(self): + zone = Zone('unit.tests.', []) + a = Record.new(zone, 'www', { + 'ttl': 60, + 'type': 'A', + 'value': '9.9.9.9', + }) + cname = Record.new(zone, 'www', { + 'ttl': 60, + 'type': 'CNAME', + 'value': 'foo.bar.com.', + }) + + # add cname to a + zone.add_record(a) + with self.assertRaises(InvalidNodeException): + zone.add_record(cname) + + # add a to cname + zone = Zone('unit.tests.', []) + zone.add_record(cname) + with self.assertRaises(InvalidNodeException): + zone.add_record(a)