--- a/pvl/hosts/tests.py Wed Feb 25 15:24:49 2015 +0200
+++ b/pvl/hosts/tests.py Wed Feb 25 15:37:46 2015 +0200
@@ -255,7 +255,73 @@
#self.assertZoneEquals(zone.host_forward(h, 'bar.domain'), {
# ('test', 'CNAME'): ['host.foo'],
#})
-
+
+ def testHostsForward(self):
+ hosts = [
+ host.Host.build('foo', 'domain',
+ ip = '192.0.2.1',
+ ip6 = '2001:db8::192.0.2.1',
+ alias = 'test',
+ ),
+ host.Host.build('bar', 'domain',
+ ip = '192.0.2.2',
+ )
+ ]
+
+ self.assertZoneEquals(zone.apply_hosts_forward(self.options, hosts, 'domain'), {
+ ('foo', 'A'): ['192.0.2.1'],
+ ('foo', 'AAAA'): ['2001:db8::c000:201'],
+ ('test', 'CNAME'): ['foo'],
+ ('bar', 'A'): ['192.0.2.2'],
+ })
+
+ def testHostsConflict(self):
+ hosts = [
+ host.Host.build('foo', 'domain',
+ ip = '192.0.2.1',
+ ),
+ host.Host.build('foo', 'domain',
+ ip = '192.0.2.2',
+ )
+ ]
+
+ with self.assertRaises(zone.HostZoneError):
+ self.assertZoneEquals(zone.apply_hosts_forward(self.options, hosts, 'domain'), { })
+
+ def testHostsAliasConflict(self):
+ hosts = [
+ host.Host.build('foo', 'domain',
+ ip = '192.0.2.1',
+ ),
+ host.Host.build('bar', 'domain',
+ ip = '192.0.2.2',
+ alias = 'foo',
+ )
+ ]
+
+ # with A first
+ with self.assertRaises(zone.HostZoneError):
+ self.assertZoneEquals(zone.apply_hosts_forward(self.options, hosts, 'domain'), { })
+
+ # also with CNAME first
+ with self.assertRaises(zone.HostZoneError):
+ self.assertZoneEquals(zone.apply_hosts_forward(self.options, reversed(hosts), 'domain'), { })
+
+ def testHostsAlias4Conflict(self):
+ hosts = [
+ host.Host.build('foo', 'domain',
+ ip = '192.0.2.1',
+ ),
+ host.Host.build('bar', 'domain',
+ ip = '192.0.2.2',
+ alias4 = 'foo',
+ )
+ ]
+
+ with self.assertRaises(zone.HostZoneError):
+ self.assertZoneEquals(zone.apply_hosts_forward(self.options, hosts, 'domain'), { })
+
+
class TestReverseZone(TestZoneMixin, unittest.TestCase):
def setUp(self):
self.options = Options()
--- a/pvl/hosts/zone.py Wed Feb 25 15:24:49 2015 +0200
+++ b/pvl/hosts/zone.py Wed Feb 25 15:37:46 2015 +0200
@@ -144,6 +144,8 @@
"""
Generate DNS ZoneRecords for for hosts within the given zone origin.
+ Verifies that there are no overlapping name/type records, or CNAME records from aliases.
+
Yields ZoneRecords in Host-order
"""
@@ -151,22 +153,22 @@
yield pvl.dns.ZoneDirective.build(None, 'ORIGIN', origin)
by_name = dict()
- by_cname = dict()
+ by_name_type = dict()
for host in hosts:
if not host.domain:
log.debug("%s: skip without domain", host)
for rr in host_forward(host, origin) :
- if rr.name in by_cname:
- raise HostZoneError(host, "{host}: CNAME {cname} conflict: {rr}".format(host=host, cname=by_cname[rr.name].name, rr=rr))
+ if (rr.name, 'CNAME') in by_name_type:
+ raise HostZoneError(host, "{host}: CNAME {cname} conflict: {rr}".format(host=host, cname=by_name_type[rr.name, 'CNAME'].name, rr=rr))
elif rr.type == 'CNAME' and rr.name in by_name:
raise HostZoneError(host, "{host}: CNAME {cname} conflict: {rr}".format(host=host, cname=rr.name, rr=by_name[rr.name]))
+ elif (rr.name, rr.type) in by_name_type:
+ raise HostZoneError(host, "{host}: {type} {name} conflict: {rr}".format(host=host, type=rr.type, name=rr.name, rr=by_name_type[rr.name, rr.type]))
by_name[rr.name] = rr
-
- if rr.type == 'CNAME':
- by_cname[rr.name] = rr
+ by_name_type[rr.name, rr.type] = rr
# preserve ordering
yield rr