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