tero@440: import ipaddr terom@669: import itertools tero@477: import pvl.args tero@440: import unittest tero@440: tero@477: from pvl.hosts import config, dhcp, zone tero@477: from pvl.hosts.host import Host tero@440: from StringIO import StringIO tero@440: tero@447: class ConfFile(StringIO): tero@440: def __init__(self, name, buffer): tero@440: StringIO.__init__(self, buffer) tero@440: self.name = name tero@440: tero@440: class TestConfig(unittest.TestCase): tero@440: def setUp(self): tero@490: self.options = pvl.args.options( tero@490: hosts_charset = 'utf-8', tero@490: hosts_domain = None, tero@490: hosts_include = None, tero@713: hosts_include_trace = None, tero@490: ) tero@440: tero@461: def assertHostEqual(self, host, host_str, attrs): tero@461: self.assertEquals(str(host), host_str) tero@461: tero@461: for attr, value in attrs.iteritems(): tero@461: self.assertEquals(getattr(host, attr), value) tero@461: tero@447: def assertHostsEqual(self, hosts, expected): tero@508: hosts = list(hosts) tero@508: tero@692: for host, expect in itertools.izip_longest(hosts, expected): tero@692: self.assertIsNotNone(host, expect) tero@692: self.assertIsNotNone(expect, host) tero@692: tero@447: host_str, attrs = expect tero@441: tero@461: self.assertHostEqual(host, host_str, attrs) tero@508: tero@461: def testApplyHostConfigDict(self): tero@504: host = config.apply_host('foo', 'test', { tero@461: 'ethernet.eth0': '00:11:22:33:44:55', tero@461: }) tero@461: tero@461: self.assertHostEqual(host, 'foo@test', dict( tero@461: ethernet = { 'eth0': '00:11:22:33:44:55' } tero@461: )) tero@502: tero@502: def testApplyHostConfigDictMulti(self): tero@504: host = config.apply_host('foo', 'test', { tero@502: 'ethernet.eth0': '00:11:22:33:44:55', tero@502: 'ethernet.eth1': '00:11:22:33:44:66', tero@502: }) tero@502: tero@502: self.assertHostEqual(host, 'foo@test', dict( tero@502: ethernet = { tero@502: 'eth0': '00:11:22:33:44:55', tero@502: 'eth1': '00:11:22:33:44:66', tero@502: } tero@502: )) tero@461: terom@661: def testApplyHostsConfigErrorExtra(self): terom@661: host = config.apply_host('foo', 'test', { terom@661: 'ethernet': '00:11:22:33:44:55', terom@661: 'ethernet.eth1': '00:11:22:33:44:66', terom@661: }) terom@661: terom@661: self.assertHostEqual(host, 'foo@test', dict( terom@661: ethernet = { terom@661: None: '00:11:22:33:44:55', terom@661: 'eth1': '00:11:22:33:44:66', terom@661: } terom@661: )) terom@661: tero@447: tero@501: def testApplyHostConfigExtensions(self): tero@504: host = config.apply_host('foo', 'test', { tero@501: 'link:50': 'foo@test', tero@501: 'link:uplink.49': 'bar@test', tero@501: }) tero@501: tero@501: self.assertHostEqual(host, 'foo@test', dict( tero@501: extensions = { tero@501: 'link': { tero@501: '50': 'foo@test', tero@501: 'uplink': { '49': 'bar@test' }, tero@501: }, tero@501: }, tero@501: )) tero@505: tero@505: def testApplyHostFqdn(self): tero@505: self.assertHostsEqual(config.apply_hosts('test', 'asdf@foo.test', { }), [ tero@505: ('asdf@foo.test', dict()), tero@505: ]) tero@501: tero@505: self.assertHostsEqual(config.apply_hosts('test', 'asdf.test2', { }), [ tero@505: ('asdf.test2@', dict()), tero@505: ]) tero@505: tero@505: def testApplyHostExpand(self): terom@733: self.assertHostsEqual(config.apply_hosts('test', 'asdf{1-3}', terom@733: { 'ip': '10.100.100.$' } terom@733: ), [ terom@733: ('asdf1@test', dict(ip4=ipaddr.IPAddress('10.100.100.1'))), terom@733: ('asdf2@test', dict(ip4=ipaddr.IPAddress('10.100.100.2'))), terom@733: ('asdf3@test', dict(ip4=ipaddr.IPAddress('10.100.100.3'))), tero@505: ]) tero@505: tero@505: def testApplyHostsFileError(self): tero@505: with self.assertRaises(config.HostConfigError): tero@505: list(config.apply_hosts_files(self.options, ['nonexistant'])) tero@505: tero@511: def testApplyHostsConfig(self): tero@505: conf_file = ConfFile('test', """ tero@505: [foo] tero@505: ip = 127.0.0.1 tero@505: tero@505: [bar] tero@505: ip = 127.0.0.2 tero@505: """) tero@511: tero@511: self.assertHostsEqual(config.apply_hosts_config(self.options, conf_file), [ terom@733: ('foo@test', dict(ip4=ipaddr.IPAddress('127.0.0.1'))), terom@733: ('bar@test', dict(ip4=ipaddr.IPAddress('127.0.0.2'))), tero@511: ]) tero@505: tero@511: def testApplyHostsConfigNested(self): tero@511: conf_file = ConfFile('test', """ tero@511: [asdf] tero@511: [[foo]] tero@511: ip = 127.0.0.1 tero@511: tero@511: [quux] tero@511: [[bar]] tero@511: ip = 127.0.0.2 tero@511: """) tero@511: tero@511: self.assertHostsEqual(config.apply_hosts_config(self.options, conf_file), [ terom@733: ('foo@asdf.test', dict(ip4=ipaddr.IPAddress('127.0.0.1'))), terom@733: ('bar@quux.test', dict(ip4=ipaddr.IPAddress('127.0.0.2'))), tero@511: ]) tero@505: tero@689: def testHostsConfigDdefaults(self): tero@689: hosts = config.apply_hosts_config(self.options, ConfFile('test', """ tero@689: boot.next-server = boot.lan tero@689: tero@689: [foo] tero@689: ip = 192.0.2.1 tero@689: ethernet.eth0 = 00:11:22:33:44:55 tero@689: boot.filename = /pxelinux.0 tero@689: """)) tero@689: tero@689: self.assertHostsEqual(hosts, [ tero@689: ('foo@test', dict( terom@733: ip4 = ipaddr.IPAddress('192.0.2.1'), tero@689: ethernet = { 'eth0': '00:11:22:33:44:55' }, tero@689: boot = { 'next-server': 'boot.lan', 'filename': '/pxelinux.0' }, tero@689: )), tero@689: ]) tero@689: tero@689: tero@689: tero@507: def testApplyIncludes(self): tero@521: self.assertHostsEqual(config.apply_hosts_files(self.options, ['etc/hosts/test']), [ terom@663: ('bar@test', dict( terom@733: ip4 = ipaddr.IPAddress('192.0.2.2'), terom@663: )), tero@513: ('foo@test', dict( terom@733: ip4 = ipaddr.IPAddress('192.0.2.1'), tero@510: )), tero@510: ]) tero@510: tero@692: def testApplyIncludesDefaults(self): tero@692: self.assertHostsEqual(config.apply_hosts_config(self.options, ConfFile('test', """ tero@692: boot.next-server = boot.lan tero@692: tero@692: include = etc/hosts/test tero@692: """)), [ tero@692: ('bar@test', dict( terom@733: ip4 = ipaddr.IPAddress('192.0.2.2'), tero@692: )), tero@692: ('foo@test', dict( terom@733: ip4 = ipaddr.IPAddress('192.0.2.1'), tero@692: )), tero@692: ]) tero@692: tero@692: tero@518: def testApplyIncludePath(self): tero@521: self.options.hosts_include = 'etc/hosts' tero@713: include_trace = [ ] tero@713: tero@713: hosts = list(config.apply_hosts_files(self.options, ['etc/zones/forward/test'], tero@713: include_trace = include_trace, tero@713: )) tero@713: tero@713: self.assertHostsEqual(hosts, [ terom@663: ('quux@asdf.test', dict( terom@733: ip4 = ipaddr.IPAddress('192.0.2.5'), tero@518: )), tero@518: ('bar@test', dict( terom@733: ip4 = ipaddr.IPAddress('192.0.2.2'), tero@518: )), terom@663: ('foo@test', dict( terom@733: ip4 = ipaddr.IPAddress('192.0.2.1'), terom@660: )), tero@518: ]) tero@518: tero@713: self.assertEqual(include_trace, [ tero@713: 'etc/zones/forward/test', tero@713: 'etc/zones/forward/test/asdf.test', tero@713: 'etc/zones/forward/test/test', tero@713: 'etc/hosts/test.d/', tero@713: 'etc/hosts/test.d/bar', tero@713: 'etc/hosts/test.d/foo', tero@713: ]) tero@713: tero@505: def testApply(self): tero@513: self.assertHostsEqual(config.apply(self.options, ['etc/hosts/example.com']), [ tero@513: ('foo@example.com', dict( terom@733: ip4 = ipaddr.IPAddress('192.0.2.1'), tero@505: ethernet = {None: '00:11:22:33:44:55'}, tero@505: )), tero@513: ('bar@example.com', dict( terom@733: ip4 = ipaddr.IPAddress('192.0.2.2'), tero@505: ethernet = {None: '01:23:45:67:89:ab'}, tero@505: )), tero@505: ]) tero@501: tero@469: class TestZoneMixin(object): tero@463: def assertZoneEquals(self, rrs, expected): tero@688: """ tero@688: Tests that the given list of ZoneRecords is equal to the given {(rr.name, rr.type): str(rr.data)} dict. tero@688: tero@688: Multiple records for the same name/type are gathered as a list. XXX: ordering tero@688: """ tero@688: tero@463: gather = { } tero@463: tero@463: for rr in rrs: tero@463: key = (rr.name.lower(), rr.type.upper()) tero@688: value = '\t'.join(rr.data) tero@688: tero@688: if key not in gather: tero@688: gather[key] = value tero@688: elif not isinstance(gather[key], list): tero@688: gather[key] = [gather[key], value] tero@688: else: tero@688: gather[key].append(value) tero@463: tero@463: self.assertDictEqual(gather, expected) tero@463: tero@469: tero@469: class TestForwardZone(TestZoneMixin, unittest.TestCase): tero@469: def testHostOutOfOrigin(self): tero@504: h = Host.build('host', 'domain', tero@504: ip = '10.0.0.1', tero@504: ) tero@463: tero@463: self.assertZoneEquals(zone.host_forward(h, 'test'), { }) tero@463: tero@464: def testHostIP(self): tero@477: h = Host.build('host', 'domain', tero@463: ip = '192.0.2.1', tero@463: ip6 = '2001:db8::192.0.2.1', tero@463: ) tero@463: tero@463: self.assertZoneEquals(zone.host_forward(h, 'domain'), { tero@688: ('host', 'A'): '192.0.2.1', tero@688: ('host', 'AAAA'): '2001:db8::c000:201', tero@463: }) tero@465: tero@466: def testHostAlias(self): tero@477: h = Host.build('host', 'domain', tero@466: ip = '192.0.2.1', tero@466: alias = 'test *.test', tero@466: ) tero@466: tero@466: self.assertEquals(h.alias, ['test', '*.test']) tero@466: tero@466: self.assertZoneEquals(zone.host_forward(h, 'domain'), { tero@688: ('host', 'A'): '192.0.2.1', tero@688: ('test', 'CNAME'): 'host', tero@688: ('*.test', 'CNAME'): 'host', tero@466: }) tero@466: tero@468: def testHostAlias46(self): tero@477: h = Host.build('host', 'domain', tero@468: ip = '192.0.2.1', tero@468: ip6 = '2001:db8::192.0.2.1', tero@468: alias4 = 'test4', tero@468: alias6 = 'test6', tero@468: ) tero@468: tero@468: self.assertZoneEquals(zone.host_forward(h, 'domain'), { tero@688: ('host', 'A'): '192.0.2.1', tero@688: ('host', 'AAAA'): '2001:db8::c000:201', tero@688: ('test4', 'A'): '192.0.2.1', tero@688: ('test6', 'AAAA'): '2001:db8::c000:201', tero@468: }) tero@468: tero@468: def testHostAlias4Missing(self): tero@477: h = Host.build('host', 'domain', tero@468: ip6 = '2001:db8::192.0.2.1', tero@468: alias4 = 'test4', tero@468: alias6 = 'test6', tero@468: ) tero@468: tero@468: with self.assertRaises(zone.HostZoneError): tero@468: self.assertZoneEquals(zone.host_forward(h, 'domain'), { }) tero@468: tero@468: def testHostAlias6Missing(self): tero@477: h = Host.build('host', 'domain', tero@468: ip = '192.0.2.1', tero@468: alias4 = 'test4', tero@468: alias6 = 'test6', tero@468: ) tero@468: tero@468: with self.assertRaises(zone.HostZoneError): tero@468: self.assertZoneEquals(zone.host_forward(h, 'domain'), { }) tero@468: tero@493: def testHostFQDN(self): tero@493: h = Host.build('host.example.net', None, tero@493: ip = '192.0.2.3', tero@493: ) tero@493: tero@493: self.assertZoneEquals(zone.host_forward(h, 'example.com'), { tero@493: tero@493: }) tero@493: tero@469: def testHostDelegate(self): tero@477: h = Host.build('host', 'example.com', tero@469: forward = 'host.example.net', tero@469: ) tero@469: tero@469: self.assertZoneEquals(zone.host_forward(h, 'example.com'), { tero@688: ('host', 'CNAME'): 'host.example.net.', tero@469: }) tero@469: tero@467: def testHostForwardAlias(self): tero@477: h = Host.build('host', 'domain', tero@467: forward = 'host.example.net', tero@467: alias = 'test', tero@467: ) tero@467: tero@467: self.assertZoneEquals(zone.host_forward(h, 'domain'), { tero@688: ('host', 'CNAME'): 'host.example.net.', tero@688: ('test', 'CNAME'): 'host', tero@467: }) tero@466: tero@470: def testHostLocation(self): tero@477: h = Host.build('host', 'domain', tero@470: ip = '192.0.2.1', tero@470: location = 'test', tero@470: ) tero@470: tero@470: self.assertEquals(h.location, ('test', 'domain')) tero@470: tero@470: self.assertZoneEquals(zone.host_forward(h, 'domain'), { tero@688: ('host', 'A'): '192.0.2.1', tero@688: ('test', 'CNAME'): 'host', tero@470: }) tero@471: tero@471: def testHostLocationDomain(self): tero@477: h = Host.build('host', 'foo.domain', tero@471: ip = '192.0.2.1', tero@471: location = 'test@bar.domain', tero@471: ) tero@471: tero@471: self.assertEquals(h.location, ('test', 'bar.domain')) tero@471: tero@471: self.assertZoneEquals(zone.host_forward(h, 'domain'), { tero@688: ('host.foo', 'A'): '192.0.2.1', tero@688: ('test.bar', 'CNAME'): 'host.foo', tero@471: }) tero@471: tero@471: def testHostLocationDomainOutOfOrigin(self): tero@477: h = Host.build('host', 'foo.domain', tero@471: ip = '192.0.2.1', tero@471: location = 'test@bar.domain', tero@471: ) tero@471: tero@471: self.assertEquals(h.location, ('test', 'bar.domain')) tero@471: tero@471: with self.assertRaises(zone.HostZoneError): tero@471: self.assertZoneEquals(zone.host_forward(h, 'foo.domain'), { tero@688: ('host', 'A'): '192.0.2.1', tero@471: }) tero@471: tero@471: # TODO tero@471: #self.assertZoneEquals(zone.host_forward(h, 'bar.domain'), { tero@471: # ('test', 'CNAME'): ['host.foo'], tero@471: #}) tero@472: tero@472: def testHostsForward(self): tero@472: hosts = [ tero@477: Host.build('foo', 'domain', tero@472: ip = '192.0.2.1', tero@472: ip6 = '2001:db8::192.0.2.1', tero@472: alias = 'test', tero@472: ), tero@477: Host.build('bar', 'domain', tero@472: ip = '192.0.2.2', tero@496: ), tero@496: Host.build('quux', 'example', tero@496: ip = '192.0.2.3', tero@496: ), tero@472: ] tero@497: tero@497: rrs = zone.apply_hosts_forward(hosts, 'domain', add_origin=True) tero@497: tero@497: # handle the $ORIGIN directive tero@497: rd = next(rrs) tero@472: tero@497: self.assertEquals(unicode(rd), '$ORIGIN\tdomain.') tero@497: tero@497: self.assertZoneEquals(rrs, { tero@688: ('foo', 'A'): '192.0.2.1', tero@688: ('foo', 'AAAA'): '2001:db8::c000:201', tero@688: ('test', 'CNAME'): 'foo', tero@688: ('bar', 'A'): '192.0.2.2', tero@688: }) tero@688: tero@688: def testHostsMultiAlias(self): tero@688: hosts = [ tero@688: Host.build('foo', 'domain', tero@688: ip = '192.0.2.1', tero@688: alias4 = 'test', tero@688: ), tero@688: Host.build('bar', 'domain', tero@688: ip = '192.0.2.2', tero@688: alias4 = 'test', tero@688: ) tero@688: ] tero@688: tero@688: self.assertZoneEquals(zone.apply_hosts_forward(hosts, 'domain', check_conflicts=False), { tero@688: ('foo', 'A'): '192.0.2.1', tero@688: ('bar', 'A'): '192.0.2.2', tero@688: ('test', 'A'): ['192.0.2.1', '192.0.2.2'], tero@472: }) tero@472: tero@472: def testHostsConflict(self): tero@472: hosts = [ tero@477: Host.build('foo', 'domain', tero@472: ip = '192.0.2.1', tero@472: ), tero@477: Host.build('foo', 'domain', tero@472: ip = '192.0.2.2', tero@472: ) tero@472: ] tero@472: tero@472: with self.assertRaises(zone.HostZoneError): tero@687: self.assertZoneEquals(zone.apply_hosts_forward(hosts, 'domain', check_conflicts=True), { }) tero@472: tero@472: def testHostsAliasConflict(self): tero@472: hosts = [ tero@477: Host.build('foo', 'domain', tero@472: ip = '192.0.2.1', tero@472: ), tero@477: Host.build('bar', 'domain', tero@472: ip = '192.0.2.2', tero@472: alias = 'foo', tero@472: ) tero@472: ] tero@472: tero@472: # with A first tero@472: with self.assertRaises(zone.HostZoneError): tero@489: self.assertZoneEquals(zone.apply_hosts_forward(hosts, 'domain'), { }) tero@472: tero@472: # also with CNAME first tero@472: with self.assertRaises(zone.HostZoneError): tero@489: self.assertZoneEquals(zone.apply_hosts_forward(reversed(hosts), 'domain'), { }) tero@472: tero@472: def testHostsAlias4Conflict(self): tero@472: hosts = [ tero@477: Host.build('foo', 'domain', tero@472: ip = '192.0.2.1', tero@472: ), tero@477: Host.build('bar', 'domain', tero@472: ip = '192.0.2.2', tero@472: alias4 = 'foo', tero@472: ) tero@472: ] tero@472: tero@472: with self.assertRaises(zone.HostZoneError): tero@687: self.assertZoneEquals(zone.apply_hosts_forward(hosts, 'domain', check_conflicts=True), { }) tero@472: tero@472: tero@469: class TestReverseZone(TestZoneMixin, unittest.TestCase): tero@473: def testHostIP(self): tero@477: h = Host.build('host', 'domain', tero@473: ip = '192.0.2.1', tero@473: ip6 = '2001:db8::192.0.2.1', tero@473: ) tero@473: tero@473: self.assertZoneEquals((rr for ip, rr in zone.host_reverse(h, ipaddr.IPNetwork('192.0.2.1/24'))), { tero@688: ('1', 'PTR'): 'host.domain.', tero@473: }) tero@473: tero@473: self.assertZoneEquals((rr for ip, rr in zone.host_reverse(h, ipaddr.IPNetwork('2001:db8::/64'))), { tero@688: ('1.0.2.0.0.0.0.c.0.0.0.0.0.0.0.0', 'PTR'): 'host.domain.', tero@473: }) tero@473: tero@473: def testHostIP4(self): tero@477: h = Host.build('host', 'domain', tero@473: ip = '192.0.2.1', tero@473: ) tero@473: tero@473: self.assertZoneEquals((rr for ip, rr in zone.host_reverse(h, ipaddr.IPNetwork('192.0.2.1/24'))), { tero@688: ('1', 'PTR'): 'host.domain.', tero@473: }) tero@474: tero@474: self.assertZoneEquals((rr for ip, rr in zone.host_reverse(h, ipaddr.IPNetwork('192.0.0.0/16'))), { tero@688: ('1.2', 'PTR'): 'host.domain.', tero@474: }) tero@474: tero@474: self.assertZoneEquals((rr for ip, rr in zone.host_reverse(h, ipaddr.IPNetwork('192.0.0.0/12'))), { tero@688: ('1.2.0', 'PTR'): 'host.domain.', tero@474: }) tero@473: tero@473: self.assertZoneEquals((rr for ip, rr in zone.host_reverse(h, ipaddr.IPNetwork('2001:db8::/64'))), { tero@473: tero@473: }) tero@473: tero@473: def testHostIP6(self): tero@477: h = Host.build('host', 'domain', tero@473: ip6 = '2001:db8::192.0.2.1', tero@473: ) tero@473: tero@473: self.assertZoneEquals((rr for ip, rr in zone.host_reverse(h, ipaddr.IPNetwork('192.0.2.1/24'))), { tero@473: }) tero@473: tero@473: self.assertZoneEquals((rr for ip, rr in zone.host_reverse(h, ipaddr.IPNetwork('2001:db8::/64'))), { tero@688: ('1.0.2.0.0.0.0.c.0.0.0.0.0.0.0.0', 'PTR'): 'host.domain.', tero@473: }) tero@473: tero@473: def testHostIPOutOfPrefix(self): tero@477: h = Host.build('host', 'domain', tero@473: ip = '192.0.2.1', tero@473: ip6 = '2001:db8::192.0.2.1', tero@473: ) tero@473: tero@473: self.assertZoneEquals((rr for ip, rr in zone.host_reverse(h, ipaddr.IPNetwork('192.0.1.0/24'))), { tero@473: tero@473: }) tero@473: tero@473: self.assertZoneEquals((rr for ip, rr in zone.host_reverse(h, ipaddr.IPNetwork('2001:db8:1::/64'))), { tero@473: tero@473: }) tero@473: tero@493: def testHostFQDN(self): tero@493: h = Host.build('host.example.net', None, tero@493: ip = '192.0.2.3', tero@493: ip6 = '2001:db8::192.0.2.3', tero@493: ) tero@493: tero@493: self.assertZoneEquals((rr for ip, rr in zone.host_reverse(h, ipaddr.IPNetwork('192.0.2.1/24'))), { tero@688: ('3', 'PTR'): 'host.example.net.', tero@493: tero@493: }) tero@493: tero@493: self.assertZoneEquals((rr for ip, rr in zone.host_reverse(h, ipaddr.IPNetwork('2001:db8::/64'))), { tero@688: ('3.0.2.0.0.0.0.c.0.0.0.0.0.0.0.0', 'PTR'): 'host.example.net.', tero@493: }) tero@493: tero@463: def testHostDelegate(self): tero@477: h = Host.build('host', 'example.com', tero@463: ip = '192.0.2.1', tero@463: ip6 = '2001:db8::192.0.2.1', tero@465: forward = '', tero@463: reverse = '1.0/28.2.0.192.in-addr.arpa', tero@463: ) tero@463: tero@463: self.assertZoneEquals(zone.host_forward(h, 'example.com'), { tero@465: tero@463: }) tero@463: tero@463: self.assertZoneEquals((rr for ip, rr in zone.host_reverse(h, ipaddr.IPNetwork('192.0.2.1/24'))), { tero@688: ('1', 'CNAME'): '1.0/28.2.0.192.in-addr.arpa.', tero@463: }) tero@464: tero@464: self.assertZoneEquals((rr for ip, rr in zone.host_reverse(h, ipaddr.IPNetwork('2001:db8::/64'))), { tero@464: tero@464: }) tero@463: tero@494: def testHosts(self): tero@494: hosts = [ tero@494: Host.build('foo', 'domain', tero@494: ip = '192.0.2.1', tero@494: ), tero@494: Host.build('bar', 'domain', tero@494: ip = '192.0.2.2', tero@494: ) tero@494: ] tero@494: tero@494: self.assertZoneEquals(zone.apply_hosts_reverse(hosts, ipaddr.IPNetwork('192.0.2.1/24')), { tero@688: ('1', 'PTR'): 'foo.domain.', tero@688: ('2', 'PTR'): 'bar.domain.', tero@494: }) tero@494: tero@494: # in ip order tero@494: self.assertZoneEquals(zone.apply_hosts_reverse(reversed(hosts), ipaddr.IPNetwork('192.0.2.1/24')), { tero@688: ('1', 'PTR'): 'foo.domain.', tero@688: ('2', 'PTR'): 'bar.domain.', tero@494: }) tero@494: tero@474: def testHostsConflict(self): tero@474: hosts = [ tero@477: Host.build('foo', 'domain', tero@474: ip = '192.0.2.1', tero@474: ), tero@477: Host.build('bar', 'domain', tero@474: ip = '192.0.2.1', tero@474: ) tero@474: ] tero@474: tero@474: with self.assertRaises(zone.HostZoneError): tero@489: self.assertZoneEquals(zone.apply_hosts_reverse(hosts, ipaddr.IPNetwork('192.0.2.1/24')), { }) tero@474: tero@474: def testHostsGenerateUnknown(self): tero@474: hosts = [ tero@477: Host.build('foo', 'domain', tero@474: ip = '192.0.2.1', tero@474: ), tero@477: Host.build('bar', 'domain', tero@474: ip = '192.0.2.5', tero@474: ), tero@474: ] tero@474: tero@489: self.assertZoneEquals(zone.apply_hosts_reverse(hosts, ipaddr.IPNetwork('192.0.2.1/29'), tero@489: unknown_host = 'ufc', tero@489: unknown_domain = 'domain', tero@489: ), { tero@688: ('1', 'PTR'): 'foo.domain.', tero@688: ('2', 'PTR'): 'ufc.domain.', tero@688: ('3', 'PTR'): 'ufc.domain.', tero@688: ('4', 'PTR'): 'ufc.domain.', tero@688: ('5', 'PTR'): 'bar.domain.', tero@688: ('6', 'PTR'): 'ufc.domain.', tero@474: }) tero@469: tero@479: class TestDhcp(unittest.TestCase): terom@669: def assertBlockEqual(self, block, (key, items, blocks)): terom@669: self.assertEqual(block.key, key) tero@697: tero@697: for _item, item in itertools.izip_longest(sorted(block.items), sorted(items)): tero@697: self.assertIsNotNone(_item, item) tero@697: self.assertIsNotNone(item, _item) tero@697: tero@697: self.assertEqual(tuple(pvl.dhcp.config.quote(field) for field in _item), item) tero@479: terom@669: for _block, expect_block in itertools.izip_longest(block.blocks, blocks): terom@669: self.assertBlockEqual(_block, expect_block) terom@669: terom@669: def assertBlocksEqual(self, blocks, expected): terom@669: for _block, block in itertools.izip_longest(blocks, expected): terom@669: self.assertIsNotNone(_block, block) terom@669: self.assertIsNotNone(block, _block) terom@669: terom@669: self.assertBlockEqual(_block, block) tero@479: tero@479: def testHost(self): tero@479: host = Host.build('foo', 'test', tero@479: ip = '192.0.2.1', tero@479: ethernet = '00:11:22:33:44:55', tero@492: owner = 'foo', tero@479: ) tero@479: tero@479: self.assertBlocksEqual(list(dhcp.dhcp_host(host)), [ tero@479: (('host', 'foo'), [ terom@669: ('option', 'host-name', "foo"), terom@669: ('fixed-address', '192.0.2.1'), terom@669: ('hardware', 'ethernet', '00:11:22:33:44:55'), terom@669: ], []) tero@492: ]) tero@492: terom@677: def testHostFQDN(self): terom@677: host = Host.build('foo.test', 'test', terom@677: ip = '192.0.2.1', terom@677: ethernet = '00:11:22:33:44:55', terom@677: ) terom@677: terom@677: self.assertBlocksEqual(list(dhcp.dhcp_host(host)), [ terom@677: (('host', 'foo.test'), [ tero@697: ('option', 'host-name', '"foo.test"'), terom@677: ('fixed-address', '192.0.2.1'), terom@677: ('hardware', 'ethernet', '00:11:22:33:44:55'), terom@677: ], []) terom@677: ]) terom@677: tero@492: def testHostStatic(self): tero@492: host = Host.build('foo', 'test', tero@492: ip = '192.0.2.1', tero@492: ) tero@492: tero@492: self.assertBlocksEqual(list(dhcp.dhcp_host(host)), [ tero@492: tero@479: ]) tero@479: tero@480: def testHostDynamic(self): tero@480: host = Host.build('foo', 'test', tero@480: ethernet = '00:11:22:33:44:55', tero@480: ) tero@480: tero@480: self.assertBlocksEqual(list(dhcp.dhcp_host(host)), [ tero@480: (('host', 'foo'), [ tero@480: ('option', 'host-name', "foo"), tero@480: ('hardware', 'ethernet', '00:11:22:33:44:55'), terom@669: ], []) tero@480: ]) tero@480: tero@480: def testHostBoot(self): tero@491: hosts = [ tero@491: Host.build('foo1', 'test', tero@491: ethernet = '00:11:22:33:44:55', tero@491: boot = 'boot.lan:debian/wheezy/pxelinux.0', tero@491: ), tero@491: Host.build('foo2', 'test', tero@491: ethernet = '00:11:22:33:44:55', tero@491: boot = 'boot.lan:', tero@491: ), tero@491: Host.build('foo3', 'test', tero@491: ethernet = '00:11:22:33:44:55', tero@491: boot = '/debian/wheezy/pxelinux.0', tero@491: ), tero@689: Host.build('foo4', 'test', tero@689: ethernet = '00:11:22:33:44:55', tero@689: boot = {'next-server': 'boot.lan', 'filename': '/debian/wheezy/pxelinux.0' }, tero@689: ), tero@491: ] tero@480: tero@491: self.assertBlocksEqual(list(dhcp.dhcp_hosts(hosts)), [ tero@491: (('host', 'foo1'), [ tero@491: ('option', 'host-name', "foo1"), tero@480: ('hardware', 'ethernet', '00:11:22:33:44:55'), tero@697: ('next-server', '"boot.lan"'), tero@697: ('filename', '"debian/wheezy/pxelinux.0"'), terom@669: ], []), tero@491: (('host', 'foo2'), [ tero@491: ('option', 'host-name', "foo2"), tero@491: ('hardware', 'ethernet', '00:11:22:33:44:55'), tero@697: ('next-server', '"boot.lan"'), terom@669: ], []), tero@491: (('host', 'foo3'), [ tero@491: ('option', 'host-name', "foo3"), tero@491: ('hardware', 'ethernet', '00:11:22:33:44:55'), tero@697: ('filename', '"/debian/wheezy/pxelinux.0"'), tero@689: ], []), tero@689: (('host', 'foo4'), [ tero@689: ('option', 'host-name', "foo4"), tero@689: ('hardware', 'ethernet', '00:11:22:33:44:55'), tero@697: ('next-server', '"boot.lan"'), tero@697: ('filename', '"/debian/wheezy/pxelinux.0"'), terom@669: ], []), tero@480: ]) tero@689: tero@483: def testHosts(self): tero@483: hosts = [ tero@483: Host.build('foo', 'test', tero@483: ip = '192.0.2.1', tero@483: ethernet = '00:11:22:33:44:55', tero@483: ), tero@483: Host.build('bar', 'test', tero@483: ip = '192.0.2.2', tero@483: ethernet = '01:23:45:67:89:ab', tero@483: ), tero@483: ] tero@483: tero@483: self.assertBlocksEqual(list(dhcp.dhcp_hosts(hosts)), [ tero@483: (('host', 'foo'), [ tero@483: ('option', 'host-name', "foo"), tero@483: ('fixed-address', '192.0.2.1'), tero@483: ('hardware', 'ethernet', '00:11:22:33:44:55'), terom@669: ], []), tero@483: (('host', 'bar'), [ tero@483: ('option', 'host-name', "bar"), tero@483: ('fixed-address', '192.0.2.2'), tero@483: ('hardware', 'ethernet', '01:23:45:67:89:ab'), terom@669: ], []), tero@483: ]) tero@483: tero@483: def testHostConflict(self): tero@483: hosts = [ tero@483: Host.build('foo', 'test1', tero@483: ethernet = '00:11:22:33:44:55', tero@483: ), tero@483: Host.build('foo', 'test2', tero@483: ethernet = '01:23:45:67:89:ab', tero@483: ), tero@483: ] tero@483: tero@483: with self.assertRaises(dhcp.HostDHCPError): tero@483: list(dhcp.dhcp_hosts(hosts)) tero@483: tero@483: def testHostMultinet(self): tero@483: hosts = [ tero@483: Host.build('foo', 'test1', tero@483: ip = '192.0.1.1', tero@483: ethernet = { 'eth1': '00:11:22:33:44:55' }, tero@483: ), tero@483: Host.build('foo', 'test2', tero@483: ip = '192.0.2.1', tero@483: ethernet = { 'eth2': '01:23:45:67:89:ab' }, tero@483: ), tero@483: ] tero@483: tero@483: self.assertBlocksEqual(list(dhcp.dhcp_hosts(hosts)), [ tero@483: (('host', 'foo-eth1'), [ tero@483: ('option', 'host-name', "foo"), tero@483: ('fixed-address', '192.0.1.1'), tero@483: ('hardware', 'ethernet', '00:11:22:33:44:55'), terom@669: ], []), tero@483: (('host', 'foo-eth2'), [ tero@483: ('option', 'host-name', "foo"), tero@483: ('fixed-address', '192.0.2.1'), tero@483: ('hardware', 'ethernet', '01:23:45:67:89:ab'), terom@669: ], []), tero@483: ]) tero@483: tero@698: def testHostSubclass(self): tero@698: hosts = [Host.build('foo', 'test', tero@698: ethernet = '00:11:22:33:44:55', tero@698: extensions = dict(dhcp=dict( tero@698: subclass = 'debian', tero@698: )), tero@698: )] tero@698: tero@698: self.assertBlocksEqual(list(dhcp.dhcp_hosts(hosts)), [ tero@698: (('host', 'foo'), [ tero@698: ('option', 'host-name', "foo"), tero@698: ('hardware', 'ethernet', '00:11:22:33:44:55'), tero@698: ], []), tero@698: (None, [ tero@700: ('subclass', '"debian"', '1:00:11:22:33:44:55'), tero@698: ], []), tero@698: ]) tero@483: tero@440: if __name__ == '__main__': tero@440: unittest.main()