pvl.hosts: support alias4/6=... for A/AAAA CNAMES
#!/usr/bin/env python
import pvl.args
import pvl.hosts
import pvl.dns.zone
import fnmatch
import ipaddr
import logging; log = logging.getLogger('pvl.hosts-dns')
import optparse
def process_hosts_names (options, hosts, domain) :
"""
Yield ZoneRecords for the given domain's hosts.
"""
for host in hosts :
if not options.forward_zone :
pass
elif host.domain == domain :
pass
elif pvl.dns.zone.join('*', host.domain) == domain :
pass
elif fnmatch.fnmatch(host.domain, domain) :
pass
else :
log.debug("%s: %s out of domain: %s", host, host.domain, domain)
continue
if host.ip :
yield pvl.dns.zone.ZoneRecord.A(host, host.ip)
if host.alias4 :
yield pvl.dns.zone.ZoneRecord.A(host.ALIAS4_FMT.format(host=host), host.ip)
if host.ip6 :
yield pvl.dns.zone.ZoneRecord.AAAA(host, host.ip6)
if host.alias6 :
yield pvl.dns.zone.ZoneRecord.AAAA(host.ALIAS6_FMT.format(host=host), host.ip6)
for alias in host.alias :
yield pvl.dns.zone.ZoneRecord.CNAME(alias, host)
for alias4 in host.alias4 :
yield pvl.dns.zone.ZoneRecord.CNAME(alias4, host.ALIAS4_FMT.format(host=host))
for alias6 in host.alias6 :
yield pvl.dns.zone.ZoneRecord.CNAME(alias6, host.ALIAS6_FMT.format(host=host))
def process_hosts_forward (options, hosts, domain) :
"""
Generate DNS ZoneRecords for the given domain's zone for hosts.
"""
by_name = dict()
by_name_type = dict()
# list of types thare are allowed to be present for a host
MULTI_TYPES = ('A', 'AAAA')
for rr in process_hosts_names(options, hosts, domain) :
if (rr.name, rr.type) in by_name_type :
raise ValueError("%s: duplicate name/type: %s: %s" % (rr.name, rr, by_name_type[(rr.name, rr.type)]))
elif rr.type in MULTI_TYPES :
by_name_type[(rr.name, rr.type)] = rr
elif rr.name in by_name :
raise ValueError("%s: duplicate name: %s: %s" % (rr.name, rr, by_name[rr.name]))
# always check these
by_name[rr.name] = rr
# preserve ordering
yield rr
def process_hosts_ips (options, hosts, prefix) :
"""
Yield (ip, fqnd) for hosts within given prefix.
"""
for host in hosts :
if prefix.version == 4 :
ip = host.ip
elif prefix.version == 6 :
ip = host.ip6
else :
raise ValueError("%s: unknown ip version: %s" % (prefix, prefix.version))
if not ip :
log.debug("%s: no ip%d", host, prefix.version)
continue
if ip not in prefix :
log.debug("%s: %s out of prefix: %s", host, ip, prefix)
continue
fqdn = host.fqdn()
log.debug("%s: ip=%s domain=%s: %s", host, ip, host.domain, fqdn)
yield ip, fqdn
def process_hosts_reverse (options, hosts, prefix) :
"""
Generate DNS ZoneRecords within the given prefix's reverse-dns zone for hosts.
"""
# collect data for records
by_ip = dict()
for ip, fqdn in process_hosts_ips(options, hosts, prefix) :
if ip in by_ip :
raise ValueError("%s: duplicate ip: %s: %s" % (fqdn, ip, by_ip[ip]))
else :
by_ip[ip] = fqdn
if options.unknown_host :
# enumerate all of them
iter_ips = prefix.iterhosts()
else :
iter_ips = sorted(by_ip)
for ip in iter_ips :
if ip in by_ip :
fqdn = by_ip[ip]
elif options.unknown_host :
fqdn = pvl.dns.zone.fqdn(options.unknown_host, options.hosts_domain)
else :
fqdn = None
log.info("%s: %s", ip, fqdn)
if fqdn :
# reverse against the reverse-dns zone origin
yield pvl.dns.zone.ZoneRecord.PTR(pvl.dns.zone.reverse_label(prefix, ip), fqdn)
def apply_zone (options, zone) :
"""
Output given ZoneRecord's
"""
for record in zone :
print unicode(record)
def main (argv) :
"""
Generate bind zonefiles from host definitions.
"""
parser = optparse.OptionParser(main.__doc__)
parser.add_option_group(pvl.args.parser(parser))
parser.add_option_group(pvl.hosts.optparser(parser))
parser.add_option('--forward-zone', metavar='DOMAIN',
help="Generate forward zone for domain")
parser.add_option('--reverse-zone', metavar='PREFIX',
help="Generate reverse zone for prefx")
parser.add_option('--unknown-host', metavar='NAME',
help="Generate records for unused IPs")
options, args = parser.parse_args(argv[1:])
pvl.args.apply(options)
# input
hosts = pvl.hosts.apply(options, args)
# process
if options.forward_zone :
apply_zone(options,
process_hosts_forward(options, hosts, options.forward_zone),
)
if options.reverse_zone :
apply_zone(options,
process_hosts_reverse(options, hosts, ipaddr.IPNetwork(options.reverse_zone)),
)
if __name__ == '__main__':
pvl.args.main(main)