pvl.hosts: support alias4/6=... for A/AAAA CNAMES
authorTero Marttila <terom@paivola.fi>
Wed, 18 Dec 2013 22:35:48 +0200
changeset 308 08176bed21e3
parent 307 cc645622024e
child 309 2b8ba955afac
pvl.hosts: support alias4/6=... for A/AAAA CNAMES
bin/pvl.hosts-dns
pvl/dns/zone.py
pvl/hosts.py
--- a/bin/pvl.hosts-dns	Tue Dec 17 17:44:47 2013 +0200
+++ b/bin/pvl.hosts-dns	Wed Dec 18 22:35:48 2013 +0200
@@ -30,21 +30,45 @@
         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 in by_name :
+        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]))
-        else :
-            by_name[rr.name] = rr
+        
+        # always check these
+        by_name[rr.name] = rr
         
         # preserve ordering
         yield rr
--- a/pvl/dns/zone.py	Tue Dec 17 17:44:47 2013 +0200
+++ b/pvl/dns/zone.py	Wed Dec 18 22:35:48 2013 +0200
@@ -312,8 +312,12 @@
         )
 
     @classmethod
-    def A (cls, name, ip, **opts) :
-        return cls(str(name), 'A', [str(ip)], **opts)
+    def A (cls, name, ip4, **opts) :
+        return cls(str(name), 'A', [str(ip4)], **opts)
+
+    @classmethod
+    def AAAA (cls, name, ip6, **opts) :
+        return cls(str(name), 'AAAA', [str(ip6)], **opts)
 
     @classmethod
     def CNAME (cls, name, host, **opts) :
--- a/pvl/hosts.py	Tue Dec 17 17:44:47 2013 +0200
+++ b/pvl/hosts.py	Wed Dec 18 22:35:48 2013 +0200
@@ -21,6 +21,10 @@
     return hosts
 
 class Host (object) :
+    # the label used for alias4/6 hosts
+    ALIAS4_FMT = '{host}-ipv4'
+    ALIAS6_FMT = '{host}-ipv6'
+
     @classmethod
     def expand (cls, options, host, range, ip, **opts) :
         host = pvl.dns.zone.parse_generate_field(host)
@@ -51,7 +55,7 @@
             yield cls.build(options, host, ip=ip, **extra)
     
     @classmethod
-    def build (cls, options, host, domain=None, ip=None, ip6=None, owner=None, boot=None, alias=None, **extra) :
+    def build (cls, options, host, domain=None, ip=None, ip6=None, owner=None, boot=None, alias=None, alias4=None, alias6=None, **extra) :
         """
             Return a Host from a config section's scalars.
         """
@@ -60,6 +64,16 @@
             alias = alias.split()
         else :
             alias = ()
+
+        if alias4 :
+            alias4 = alias4.split()
+        else :
+            alias4 = ()
+
+        if alias6 :
+            alias6 = alias6.split()
+        else :
+            alias6 = ()
         
         ethernet = { }
 
@@ -87,11 +101,13 @@
                 ip6         = ipaddr.IPv6Address(ip6) if ip6 else None,
                 ethernet    = ethernet,
                 alias       = alias,
+                alias4      = alias4,
+                alias6      = alias6,
                 owner       = owner,
                 boot        = boot,
         )
 
-    def __init__ (self, host, domain=None, ip=None, ip6=None, ethernet={ }, alias=(), owner=None, boot=None) :
+    def __init__ (self, host, domain=None, ip=None, ip6=None, ethernet={ }, alias=(), owner=None, boot=None, alias4=None, alias6=None) :
         """
             host        - str
             domain      - str
@@ -100,6 +116,8 @@
             ethernet    - { index: ethernet }
             alias       - list
             owner       - str: LDAP uid
+            alias4      - list (CNAME -> A)
+            alias6      - list (CNAME -> AAAA)
         """
         self.host = host
         self.domain = domain
@@ -107,6 +125,8 @@
         self.ip6 = ip6
         self.ethernet = ethernet
         self.alias = alias
+        self.alias4 = alias4
+        self.alias6 = alias6
         self.owner = owner
         self.boot = boot