# HG changeset patch # User Tero Marttila # Date 1425936673 -7200 # Node ID 3104fdf7ea269fea1d4d834038b4cf07ecbffff4 # Parent 6ba76ac0bc7285d056728c511d353cb64b69fac1 pvl.hosts.hosts: drop support for instanced ip.* in favor of improved interface:ip.* = diff -r 6ba76ac0bc72 -r 3104fdf7ea26 pvl/hosts/host.py --- a/pvl/hosts/host.py Mon Mar 09 23:21:43 2015 +0200 +++ b/pvl/hosts/host.py Mon Mar 09 23:31:13 2015 +0200 @@ -138,7 +138,7 @@ # empty value return False -def parse_dict(value, parse): +def parse_dict(value, parse, **opts): if not value: return { } @@ -147,7 +147,7 @@ else: values = {None: value} - return { instance: parse(value) for instance, value in values.iteritems() } + return {instance: parse(value, **opts) for instance, value in values.iteritems()} class Host (object) : """ @@ -184,17 +184,10 @@ 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, - ip4 = ip4.get(None), - ip6 = ip6.get(None), - ip = ip, + ip4 = parse_ip(ip, ipaddr.IPv4Address), + ip6 = parse_ip(ip6, ipaddr.IPv6Address), ethernet = parse_dict(ethernet, parse_ethernet), owner = owner, location = parse_location(location, domain), @@ -210,7 +203,6 @@ def __init__ (self, name, domain, ip4=None, ip6=None, - ip={}, ethernet={ }, owner=None, location=None, @@ -225,7 +217,6 @@ domain - str 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 @@ -245,7 +236,6 @@ self.domain = domain self.ip4 = ip4 self.ip6 = ip6 - self.ip = ip self.ethernet = ethernet self.alias = alias self.alias4 = alias4 @@ -263,8 +253,8 @@ Stable sort ordering """ - if self.ip: - return self.ip + if self.ip4: + return self.ip4 else: # sorts first return ipaddr.IPAddress(0) @@ -274,19 +264,21 @@ Yield (sublabel, ipaddr) records. """ - for sublabel, (ip4, ip6) in self.ip.iteritems(): + if self.ip4: + yield None, self.ip4 - if ip4: - yield sublabel, ip4 - - if ip6: - yield sublabel, ip6 + if self.ip6: + yield None, self.ip6 for extension in self.extensions.itervalues(): for sublabel, ip in extension.addresses(): yield sublabel, ip def fqdn (self): + """ + Return DNS FQDN for this host in its domain. + """ + if self.domain: return pvl.dns.fqdn(self.name, self.domain) else: @@ -299,10 +291,16 @@ class HostExtension (object): """ - Extension hooks + Base class for Host.EXTENSIONS + + Provides default no-op behaviours for extension hooks. """ def addresses (self): + """ + Yield additional (sublabel, ipaddr) records. + """ + return () def extension (cls): diff -r 6ba76ac0bc72 -r 3104fdf7ea26 pvl/hosts/interface.py --- a/pvl/hosts/interface.py Mon Mar 09 23:21:43 2015 +0200 +++ b/pvl/hosts/interface.py Mon Mar 09 23:31:13 2015 +0200 @@ -1,26 +1,69 @@ +import collections import ipaddress, ipaddr # XXX: conversion import pvl.hosts +import pvl.hosts.host -def parse_interfaces(interfaces): - for interface, value in interfaces.iteritems(): - if not isinstance(value, dict): - yield (interface, None), ipaddress.ip_interface(value) - else: - for unit, ip in value.iteritems(): - yield (interface, int(unit)), ipaddress.ip_interface(value) +class HostInterface(object): + """ + A single host-interface. + """ + ip4 = None + + def __init__(self, name): + self.name = name + + def __str__(self): + return self.name + @pvl.hosts.extension -class HostInterface(object): +class HostInterfaces(object): + """ + A host with multiple sub-interfaces. + + Typically used for point-to-point interfaces between routers. For multi-homed hosts, it might make + more sense to use multiple hosts in different domains. + + [foo] + interface:ip.eth0 = 10.255.1.1/30 + + [bar] + interface:ip.eth1 = 10.255.1.2/30 + """ + EXTENSION = 'interface' @classmethod - def build (cls, **interfaces): - return cls(dict(parse_interfaces(interfaces))) + def build (cls, ip={}): + interfaces = collections.defaultdict(HostInterface) + + for iface, ip in pvl.hosts.host.parse_dict(ip, parse=ipaddress.ip_interface).iteritems(): + if iface in interfaces: + iface = interfaces[iface] + else: + iface = interfaces[iface] = HostInterface(iface) + + interfaces[iface].ip4 = ip + + return cls(interfaces) def __init__ (self, interfaces): self.interfaces = interfaces def addresses (self): - for (iface, unit), ip in self.interfaces.iteritems(): - # XXX: ipaddr - yield iface, ipaddr.IPAddress(str(ip.ip)) + """ + Yield additional sub-addresses for host interfaces. + """ + + for iface in self: + if iface.ip4: + # XXX: convert + yield iface.name, ipaddr.IPv4Address(str(iface.ip4.ip)) + + def __iter__(self): + """ + HostInterface's with stable ordering. + """ + + return iter(sorted(self.interfaces.itervalues(), key=str)) +