# HG changeset patch # User Tero Marttila # Date 1425916818 -7200 # Node ID 45bedeba92e5ebed73fa5cfe166eedc7139e3473 # Parent ddb77f32b35ab2ee07d404f27dde6eb7776b6da3 pvl.hosts: rename Host.ip -> Host.ip4; support instanced ip.foo = ... for foo.host A .... sub-labels diff -r ddb77f32b35a -r 45bedeba92e5 pvl/hosts/dhcp.py --- a/pvl/hosts/dhcp.py Sat Mar 07 16:31:11 2015 +0200 +++ b/pvl/hosts/dhcp.py Mon Mar 09 18:00:18 2015 +0200 @@ -24,8 +24,8 @@ yield 'option', 'host-name', host.name yield 'hardware', 'ethernet', pvl.dhcp.config.Field(ethernet) - if host.ip: - yield 'fixed-address', pvl.dhcp.config.Field(str(host.ip)) + if host.ip4: + yield 'fixed-address', pvl.dhcp.config.Field(str(host.ip4)) for bootopt in ('next-server', 'filename'): if bootopt in host.boot: diff -r ddb77f32b35a -r 45bedeba92e5 pvl/hosts/host.py --- a/pvl/hosts/host.py Sat Mar 07 16:31:11 2015 +0200 +++ b/pvl/hosts/host.py Mon Mar 09 18:00:18 2015 +0200 @@ -176,10 +176,16 @@ This handles all string parsing to our data types. """ + ip4 = parse_dict(ip, ipaddr.IPv4Address) + ip6 = parse_dict(ip6, ipaddr.IPv6Address) + + ip = {label: (ip4.get(label), ip6.get(label)) for label in set(ip4) | set(ip6)} + return cls(name, domain = domain, - ip = parse_ip(ip, ipaddr.IPv4Address), - ip6 = parse_ip(ip6, ipaddr.IPv6Address), + ip4 = ip4.get(None), + ip6 = ip6.get(None), + ip = ip, ethernet = parse_dict(ethernet, parse_ethernet), owner = owner, location = parse_location(location, domain), @@ -194,7 +200,8 @@ ) def __init__ (self, name, domain, - ip=None, ip6=None, + ip4=None, ip6=None, + ip={}, ethernet={ }, owner=None, location=None, @@ -207,8 +214,9 @@ """ name - str domain - str - ip - ipaddr.IPv4Address - ip6 - ipaddr.IPv6Address + ip4 - primary ipaddr.IPv4Address + ip6 - primary ipaddr.IPv6Address + ip - secondary { index: (ip4, ip6) } interface addresses ethernet - { index: ethernet } alias - [ str ]: generate CNAMEs for given relative names owner - str: LDAP uid @@ -226,8 +234,9 @@ self.name = name self.domain = domain + self.ip4 = ip4 + self.ip6 = ip6 self.ip = ip - self.ip6 = ip6 self.ethernet = ethernet self.alias = alias self.alias4 = alias4 diff -r ddb77f32b35a -r 45bedeba92e5 pvl/hosts/tests.py --- a/pvl/hosts/tests.py Sat Mar 07 16:31:11 2015 +0200 +++ b/pvl/hosts/tests.py Mon Mar 09 18:00:18 2015 +0200 @@ -99,10 +99,12 @@ ]) def testApplyHostExpand(self): - self.assertHostsEqual(config.apply_hosts('test', 'asdf{1-3}', { 'ip': '10.100.100.$' }), [ - ('asdf1@test', dict(ip=ipaddr.IPAddress('10.100.100.1'))), - ('asdf2@test', dict(ip=ipaddr.IPAddress('10.100.100.2'))), - ('asdf3@test', dict(ip=ipaddr.IPAddress('10.100.100.3'))), + self.assertHostsEqual(config.apply_hosts('test', 'asdf{1-3}', + { 'ip': '10.100.100.$' } + ), [ + ('asdf1@test', dict(ip4=ipaddr.IPAddress('10.100.100.1'))), + ('asdf2@test', dict(ip4=ipaddr.IPAddress('10.100.100.2'))), + ('asdf3@test', dict(ip4=ipaddr.IPAddress('10.100.100.3'))), ]) def testApplyHostsFileError(self): @@ -119,8 +121,8 @@ """) self.assertHostsEqual(config.apply_hosts_config(self.options, conf_file), [ - ('foo@test', dict(ip=ipaddr.IPAddress('127.0.0.1'))), - ('bar@test', dict(ip=ipaddr.IPAddress('127.0.0.2'))), + ('foo@test', dict(ip4=ipaddr.IPAddress('127.0.0.1'))), + ('bar@test', dict(ip4=ipaddr.IPAddress('127.0.0.2'))), ]) def testApplyHostsConfigNested(self): @@ -135,8 +137,8 @@ """) self.assertHostsEqual(config.apply_hosts_config(self.options, conf_file), [ - ('foo@asdf.test', dict(ip=ipaddr.IPAddress('127.0.0.1'))), - ('bar@quux.test', dict(ip=ipaddr.IPAddress('127.0.0.2'))), + ('foo@asdf.test', dict(ip4=ipaddr.IPAddress('127.0.0.1'))), + ('bar@quux.test', dict(ip4=ipaddr.IPAddress('127.0.0.2'))), ]) def testHostsConfigDdefaults(self): @@ -151,7 +153,7 @@ self.assertHostsEqual(hosts, [ ('foo@test', dict( - ip = ipaddr.IPAddress('192.0.2.1'), + ip4 = ipaddr.IPAddress('192.0.2.1'), ethernet = { 'eth0': '00:11:22:33:44:55' }, boot = { 'next-server': 'boot.lan', 'filename': '/pxelinux.0' }, )), @@ -162,10 +164,10 @@ def testApplyIncludes(self): self.assertHostsEqual(config.apply_hosts_files(self.options, ['etc/hosts/test']), [ ('bar@test', dict( - ip = ipaddr.IPAddress('192.0.2.2'), + ip4 = ipaddr.IPAddress('192.0.2.2'), )), ('foo@test', dict( - ip = ipaddr.IPAddress('192.0.2.1'), + ip4 = ipaddr.IPAddress('192.0.2.1'), )), ]) @@ -176,10 +178,10 @@ include = etc/hosts/test """)), [ ('bar@test', dict( - ip = ipaddr.IPAddress('192.0.2.2'), + ip4 = ipaddr.IPAddress('192.0.2.2'), )), ('foo@test', dict( - ip = ipaddr.IPAddress('192.0.2.1'), + ip4 = ipaddr.IPAddress('192.0.2.1'), )), ]) @@ -194,13 +196,13 @@ self.assertHostsEqual(hosts, [ ('quux@asdf.test', dict( - ip = ipaddr.IPAddress('192.0.2.5'), + ip4 = ipaddr.IPAddress('192.0.2.5'), )), ('bar@test', dict( - ip = ipaddr.IPAddress('192.0.2.2'), + ip4 = ipaddr.IPAddress('192.0.2.2'), )), ('foo@test', dict( - ip = ipaddr.IPAddress('192.0.2.1'), + ip4 = ipaddr.IPAddress('192.0.2.1'), )), ]) @@ -216,11 +218,11 @@ def testApply(self): self.assertHostsEqual(config.apply(self.options, ['etc/hosts/example.com']), [ ('foo@example.com', dict( - ip = ipaddr.IPAddress('192.0.2.1'), + ip4 = ipaddr.IPAddress('192.0.2.1'), ethernet = {None: '00:11:22:33:44:55'}, )), ('bar@example.com', dict( - ip = ipaddr.IPAddress('192.0.2.2'), + ip4 = ipaddr.IPAddress('192.0.2.2'), ethernet = {None: '01:23:45:67:89:ab'}, )), ]) diff -r ddb77f32b35a -r 45bedeba92e5 pvl/hosts/zone.py --- a/pvl/hosts/zone.py Sat Mar 07 16:31:11 2015 +0200 +++ b/pvl/hosts/zone.py Mon Mar 09 18:00:18 2015 +0200 @@ -31,15 +31,21 @@ elif host.forward is None: # forward - if host.ip : - log.info("%s: ip: %s@%s A %s", host, label, origin, host.ip) + for sublabel, (ip4, ip6) in host.ip.iteritems(): + if sublabel: + sublabel = pvl.dns.join(sublabel, label) + else: + sublabel = label + + if ip4: + log.info("%s: ip: %s@%s A %s", host, sublabel, origin, ip4) - yield pvl.dns.ZoneRecord.A(label, host.ip) + yield pvl.dns.ZoneRecord.A(sublabel, ip4) - if host.ip6 : - log.info("%s: ip6: %s@%s AAAA %s", host, label, origin, host.ip6) + if ip6: + log.info("%s: ip6: %s@%s AAAA %s", host, label, origin, ip6) - yield pvl.dns.ZoneRecord.AAAA(label, host.ip6) + yield pvl.dns.ZoneRecord.AAAA(sublabel, ip6) else: log.info("%s: skip forward", host) @@ -57,10 +63,10 @@ yield pvl.dns.ZoneRecord.CNAME(pvl.dns.relative(origin, host.domain, alias), label) for alias in host.alias4: - if not host.ip: - raise HostZoneError(host, "alias4={host.alias4} without ip=".format(host=host)) + if not host.ip4: + raise HostZoneError(host, "alias4={host.alias4} without ip4=".format(host=host)) - yield pvl.dns.ZoneRecord.A(pvl.dns.relative(origin, host.domain, alias), host.ip) + yield pvl.dns.ZoneRecord.A(pvl.dns.relative(origin, host.domain, alias), host.ip4) for alias in host.alias6: if not host.ip6: @@ -72,50 +78,54 @@ """ Yield (ipaddr.IPAddress, ZoneRecord) tuples for host within given prefix's reverse-dns zone. """ - - if prefix.version == 4 : - ip = host.ip - - # reverse= is IPv4-only - reverse = host.reverse - - elif prefix.version == 6 : - ip = host.ip6 - - # if reverse= is set, always omit, for lack of reverse6= - reverse = None if host.reverse is None else False - - else : - raise ValueError("%s: unknown ip version: %s" % (prefix, prefix.version)) - - if not ip : - log.debug("%s: no ip%d", host, prefix.version) - return + + for sublabel, (ip4, ip6) in host.ip.iteritems(): + if prefix.version == 4: + ip = ip4 + + # reverse= is IPv4-only + reverse = host.reverse - if ip not in prefix : - log.debug("%s: %s out of prefix: %s", host, ip, prefix) - return - - # relative label - label = pvl.dns.reverse_label(prefix, ip) - - if reverse: - alias = pvl.dns.fqdn(reverse) - - log.info("%s %s[%s]: CNAME %s", host, prefix, ip, alias) + elif prefix.version == 6: + ip = ip6 + + # if reverse= is set, always omit, for lack of reverse6= + reverse = None if host.reverse is None else False - yield ip, pvl.dns.zone.ZoneRecord.CNAME(label, alias) - - elif reverse is None : - fqdn = host.fqdn() + else: + raise ValueError("%s: unknown ip version: %s" % (prefix, prefix.version)) - log.info("%s %s[%s]: PTR %s", host, prefix, ip, fqdn) + if not ip: + log.debug("%s: no ip%d", host, prefix.version) + continue - yield ip, pvl.dns.zone.ZoneRecord.PTR(label, fqdn) + if ip not in prefix: + log.debug("%s: %s out of prefix: %s", host, ip, prefix) + continue + + # relative label + label = pvl.dns.reverse_label(prefix, ip) + + if reverse: + alias = pvl.dns.fqdn(reverse) + + log.info("%s %s[%s]: CNAME %s", host, prefix, ip, alias) - else: - log.info("%s %s[%s]: omit", host, prefix, ip) - + yield ip, pvl.dns.zone.ZoneRecord.CNAME(label, alias) + + elif reverse is None: + fqdn = host.fqdn() + + if sublabel: + fqdn = pvl.dns.join(sublabel, fqdn) + + log.info("%s %s[%s]: PTR %s", host, prefix, ip, fqdn) + + yield ip, pvl.dns.zone.ZoneRecord.PTR(label, fqdn) + + else: + log.info("%s %s[%s]: omit", host, prefix, ip) + def apply_hosts_forward (hosts, origin, add_origin = False, check_conflicts = False,