--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pvl/config/bind/zone.py Sun Jul 12 02:14:34 2009 +0300
@@ -0,0 +1,355 @@
+"""
+ Configuration file output for the ISC DNS server: BIND
+"""
+
+from .. import file
+
+class Item (file.Item) :
+ """
+ Item that knows how to format comments
+ """
+
+ COMMENT_PREFIX = ';'
+
+class Zone (Item, file.Contents) :
+ """
+ A zone containing a bunch of directives, resource records and comments
+ """
+
+ def __init__ (self, ttl=None, comment=None) :
+ """
+ @param name the name of the zonefile, for status stuff
+ @param path the path to the zonefile
+ @param ttl default TTL to use
+ """
+
+ Item.__init__(self, [comment])
+ file.Contents.__init__(self)
+
+ if ttl :
+ self.add(TTLDirective(ttl))
+
+class Comment (Item) :
+ """
+ A comment, is, well, a comment :)
+ """
+
+ def __init__ (self, comment) :
+ """
+ @param comment the comment string
+ """
+
+ Item.__init__(self, [comment])
+
+ # only need to iterate over our comments
+ iter_lines = Item.iter_comments
+
+class Label (object) :
+ """
+ A label, as used in a ResourceRecord, either as the label, or the rdata for various resource types
+
+ You can also use strs, this just implements a __str__ method
+ """
+
+ def __init__ (self, label) :
+ """
+ @param label the literal label to use
+ """
+
+ self.label = label
+
+ def __str__ (self) :
+ return self.label
+
+class Origin (Label) :
+ """
+ A label that represents the zone's origin
+ """
+
+ def __init__ (self) :
+ pass
+
+ def __str__ (self) :
+ return '@'
+
+class FQDN (Label) :
+ """
+ A label that represents the given external domain (i.e. this adds the . to the end that people always forget).
+ """
+
+ def __init__ (self, fqdn) :
+ self.fqdn = fqdn
+
+ def __str__ (self) :
+ return "%s." % (self.fqdn, )
+
+class Interval (object) :
+ """
+ A time interval suitable for use in SOA records
+ """
+
+ def __init__ (self, s=None, m=None, h=None, d=None) :
+ """
+ @param s seconds
+ @param m minutes
+ @param h hours
+ @param d days
+ """
+
+ self.s = s
+ self.m = m
+ self.h = h
+ self.d = d
+
+ def __str__ (self) :
+ """
+ If only seconds were given, just return those directly, otherwise, apply units
+ """
+
+ if self.s and not self.m and not self.h and not self.d :
+ return str(self.s)
+
+ else :
+ return "%s%s%s%s" % (
+ "%ds" % self.s if self.s else '',
+ "%dm" % self.m if self.m else '',
+ "%dh" % self.h if self.h else '',
+ "%dd" % self.d if self.d else ''
+ )
+
+class ResourceRecord (Item) :
+ """
+ A generic resource record for a BIND zone file
+ """
+
+ def __init__ (self, label, type, rdata, cls='IN', ttl=None, **kwargs) :
+ """
+ @param label the "name" of this record, or None to referr to the previous record's label
+ @param type the type as a string ('A', 'TXT', etc.)
+ @param rdata the rdata, as a raw string
+ @param cls the class, e.g. 'IN'
+ @param ttl the time-to-live value in seconds, or None to omit it
+ """
+
+ super(ResourceRecord, self).__init__(**kwargs)
+
+ self.label = label
+ self.type = type
+ self.rdata = rdata
+ self.cls = cls
+ self.ttl = ttl
+
+ def iter_lines (self) :
+ """
+ Just format the lines, eh
+ """
+
+ # prefix comments
+ for line in self.iter_comments() :
+ yield line
+
+ # then format the line
+ # XXX: TTL?
+ yield "%-30s %-4s%-4s %-8s %s" % (self.label if self.label is not None else '', str(self.ttl) if self.ttl else '', self.cls, self.type, self.rdata)
+
+class SOA (ResourceRecord) :
+ """
+ "Identifies the start of a zone of authority", must be the first record
+ """
+
+ def __init__ (self, label, primary_ns, hostmaster, serial, refresh, retry, expire, minimum, **kwargs) :
+ """
+ @param label the "name" of the zone, usually ORIGIN
+ @param primary_ns the address of the primary NS server
+ @param hostmaster the mailbox of the zone's hostmaster
+ @param serial the serial number of the zone as an integer
+ @param refresh time interval between zone refreshes in seconds
+ @param retry time interval between retrys for failed refreshes
+ @param expire time interval before zone data can no longer be considered authorative
+ @param minimum minimum TTL for RRs in this zone
+ """
+
+ super(SOA, self).__init__(label, 'SOA', "%s %s ( %s %s %s %s %s )" % (
+ primary_ns, hostmaster, serial, refresh, retry, expire, minimum
+ ), **kwargs)
+
+class A (ResourceRecord) :
+ """
+ An IPv4 forward address
+ """
+
+ def __init__ (self, label, addr, **kwargs) :
+ """
+ @param label the "name" of the address
+ @param addr the IPv4 target address
+ """
+
+ assert(addr.is_v4())
+
+ super(A, self).__init__(label, 'A', addr, **kwargs)
+
+class AAAA (ResourceRecord) :
+ """
+ An IPv6 forward address
+ """
+
+ def __init__ (self, label, addr, **kwargs) :
+ """
+ @param label the "name" of the address
+ @param addr the IPv6 target address
+ """
+
+ assert(addr.is_v6())
+
+ super(AAAA, self).__init__(label, 'AAAA', addr.strCompressed(), **kwargs)
+
+class CNAME (ResourceRecord) :
+ """
+ A canonical-name alias
+ """
+
+ def __init__ (self, label, target, **kwargs) :
+ """
+ @param label the "name" of the alias
+ @param target the alias target
+ """
+
+ super(CNAME, self).__init__(label, 'CNAME', target, **kwargs)
+
+class TXT (ResourceRecord) :
+ """
+ A human-readable information record
+ """
+
+ def __init__ (self, label, text, **kwargs) :
+ """
+ @param label the "name" of the text record
+ @param text the text data, shouldn't contain any quotes...
+ """
+
+ # XXX: escaping?
+ super(TXT, self).__init__(label, 'TXT', '"%s"' % text, **kwargs)
+
+class MX (ResourceRecord) :
+ """
+ A mail-exchange definition
+ """
+
+ def __init__ (self, label, pref, exchange, **kwargs) :
+ """
+ @param label the "name" of the domain to handle mail for
+ @param pref the numerical preference for this exchange
+ @param exchange the domain name of the mail exchange (SMTP server)
+ """
+
+ super(MX, self).__init__(label, 'MX', "%d %s" % (pref, exchange), **kwargs)
+
+class NS (ResourceRecord) :
+ """
+ An authorative name server
+ """
+
+ def __init__ (self, label, nsname, **kwargs) :
+ """
+ @param label the "name" of the domain to have a nameserver for
+ @param nsname the name of the nameserver
+ """
+
+ super(NS, self).__init__(label, 'NS', nsname)
+
+class PTR (ResourceRecord) :
+ """
+ An IPv4/IPv6 reverse address
+ """
+
+ def __init__ (self, addr, name, **kwargs) :
+ """
+ @param addr the addr.IP to map via in-addr.arpa
+ @param name the name to map the address to
+ """
+
+ # XXX: quick hack, this gives an absolute name
+ label = addr.reverseName()
+
+ super(PTR, self).__init__(label, 'PTR', name)
+
+class Directive (Item) :
+ """
+ Special directives that can be used in zone files to control behaviour
+ """
+
+ def __init__ (self, name, *args, **kwargs) :
+ """
+ @param name the $NAME bit
+ @param args optional list of space-seprated arguments, Nones are ignored
+ """
+
+ super(Directive, self).__init__(**kwargs)
+
+ self.name = name
+ self.args = [arg for arg in args if arg is not None]
+
+ def iter_lines (self) :
+ # prefix comments
+ for line in self.iter_comments() :
+ yield line
+
+ # then format it
+ yield "$%s%s" % (self.name, (' ' + ' '.join(str(arg) for arg in self.args)) if self.args else '')
+
+class OriginDirective (Directive) :
+ """
+ Set the origin used to resolve the zone's labels.
+
+ Note that the origin label is not absolute by default - use FQDN for that
+ """
+
+ def __init__ (self, origin, **kwargs) :
+ """
+ @param origin the origin label
+ """
+
+ super(OriginDirective, self).__init__('ORIGIN', origin, **kwargs)
+
+class TTLDirective (Directive) :
+ """
+ Set the TTL used for records by default
+ """
+
+ def __init__ (self, ttl, **kwargs) :
+ """
+ @param ttl the new ttl to use
+ """
+
+ super(TTLDirective, self).__init__('TTL', ttl, **kwargs)
+
+class IncludeDirective (Directive) :
+ """
+ Include another zoen file, optionally with a different origin
+ """
+
+ def __init__ (self, filename, origin=None, **kwargs) :
+ """
+ @param filename the zone file to include
+ @param origin the optional origin to process the zonefile with
+ """
+
+ super(IncludeDirective, self).__init__('INCLUDE', filename, origin, **kwargs)
+
+class GenerateDirective (Directive) :
+ """
+ Generate a bunch of numbered records using an expression for the label and rdata.
+
+ At the simplest, any "$" in the expression is replaced with the value of the iterator.
+ """
+
+ def __init__ (self, range, lhs, type, rhs, ttl=None, cls=None, **kwargs) :
+ """
+ @param range (start, stop, step) tuple
+ @param lhs expression to generate the label
+ @param type the resource record type
+ @param rhs expression to generate the rdata
+ """
+
+ super(GenerateDirective, self).__init__('GENERATE', '%d-%d' % range, lhs, ttl, cls, type, rhs, **kwargs)
+