# HG changeset patch # User Tero Marttila # Date 1425923230 -7200 # Node ID 5770ed34c1f0213ba3587517891b5634d4c93b87 # Parent 45bedeba92e5ebed73fa5cfe166eedc7139e3473 pvl.hosts: extension mechanism diff -r 45bedeba92e5 -r 5770ed34c1f0 pvl/hosts/__init__.py --- a/pvl/hosts/__init__.py Mon Mar 09 18:00:18 2015 +0200 +++ b/pvl/hosts/__init__.py Mon Mar 09 19:47:10 2015 +0200 @@ -7,4 +7,5 @@ from pvl.hosts.host import ( HostError, Host, + extension, ) diff -r 45bedeba92e5 -r 5770ed34c1f0 pvl/hosts/host.py --- a/pvl/hosts/host.py Mon Mar 09 18:00:18 2015 +0200 +++ b/pvl/hosts/host.py Mon Mar 09 19:47:10 2015 +0200 @@ -154,10 +154,18 @@ A host is a network node that can have multiple ethernet interfaces, and multiple IP addresses in different domains. """ - # the label used for alias4/6 hosts - ALIAS4_FMT = '{host}-ipv4' - ALIAS6_FMT = '{host}-ipv6' - + EXTENSIONS = { } + + @classmethod + def build_extensions(cls, extensions): + for extension, value in extensions.iteritems(): + extension_cls = cls.EXTENSIONS.get(extension) + + if extension_cls: + yield extension, extension_cls.build(**value) + else: + log.warning("skip unknown extension: %s", extension) + @classmethod def build (cls, name, domain, ip=None, ip6=None, @@ -181,6 +189,7 @@ ip = {label: (ip4.get(label), ip6.get(label)) for label in set(ip4) | set(ip6)} + return cls(name, domain = domain, ip4 = ip4.get(None), @@ -196,7 +205,7 @@ reverse = parse_str(reverse), down = parse_bool(down), boot = parse_dhcp_boot(boot), - extensions = extensions, + extensions = dict(cls.build_extensions(extensions)), ) def __init__ (self, name, domain, @@ -260,6 +269,23 @@ # sorts first return ipaddr.IPAddress(0) + def addresses (self): + """ + Yield (sublabel, ipaddr) records. + """ + + for sublabel, (ip4, ip6) in self.ip.iteritems(): + + if ip4: + yield sublabel, ip4 + + if ip6: + yield sublabel, ip6 + + for extension in self.extensions.itervalues(): + for sublabel, ip in extension.addresses(): + yield sublabel, ip + def fqdn (self): if self.domain: return pvl.dns.fqdn(self.name, self.domain) @@ -270,3 +296,19 @@ return "{self.name}@{domain}".format(self=self, domain = self.domain or '', ) + +class HostExtension (object): + """ + Extension hooks + """ + + def addresses (self): + return () + +def extension (cls): + """ + Register an extension class + """ + + Host.EXTENSIONS[cls.EXTENSION] = cls + diff -r 45bedeba92e5 -r 5770ed34c1f0 pvl/hosts/zone.py --- a/pvl/hosts/zone.py Mon Mar 09 18:00:18 2015 +0200 +++ b/pvl/hosts/zone.py Mon Mar 09 19:47:10 2015 +0200 @@ -31,21 +31,24 @@ elif host.forward is None: # forward - for sublabel, (ip4, ip6) in host.ip.iteritems(): + for sublabel, ip in host.addresses(): 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) + if ip.version == 4: + log.info("%s: ip: %s@%s A %s", host, sublabel, origin, ip) - yield pvl.dns.ZoneRecord.A(sublabel, ip4) + yield pvl.dns.ZoneRecord.A(sublabel, ip) - if ip6: - log.info("%s: ip6: %s@%s AAAA %s", host, label, origin, ip6) + elif ip.version == 6: + log.info("%s: ip6: %s@%s AAAA %s", host, label, origin, ip) - yield pvl.dns.ZoneRecord.AAAA(sublabel, ip6) + yield pvl.dns.ZoneRecord.AAAA(sublabel, ip) + + else: + raise ValueError(ip) else: log.info("%s: skip forward", host) @@ -79,30 +82,22 @@ Yield (ipaddr.IPAddress, ZoneRecord) tuples for host within given prefix's reverse-dns zone. """ - for sublabel, (ip4, ip6) in host.ip.iteritems(): - if prefix.version == 4: - ip = ip4 - - # reverse= is IPv4-only - reverse = host.reverse - - 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 - - else: - raise ValueError("%s: unknown ip version: %s" % (prefix, prefix.version)) - - if not ip: - log.debug("%s: no ip%d", host, prefix.version) + for sublabel, ip in host.addresses(): + if ip.version != prefix.version: continue if ip not in prefix: log.debug("%s: %s out of prefix: %s", host, ip, prefix) continue - + + if ip.version == 4: + # reverse= is IPv4-only + reverse = host.reverse + + elif prefix.version == 6: + # if reverse= is set, always omit, for lack of reverse6= + reverse = None if host.reverse is None else False + # relative label label = pvl.dns.reverse_label(prefix, ip)