sqlalchemy api changes
[invirt/packages/invirt-dns.git] / invirt-dns
index d5fa021..5b24d31 100755 (executable)
@@ -45,7 +45,7 @@ class DatabaseAuthority(common.ResolverBase):
         for i in range(3):
             try:
                 value = self._lookup_unsafe(name, cls, type, timeout = None)
-            except (psycopg2.OperationalError, sqlalchemy.exceptions.SQLError):
+            except (psycopg2.OperationalError, sqlalchemy.exceptions.DBAPIError):
                 if i == 2:
                     raise
                 print "Reloading database"
@@ -147,9 +147,9 @@ class DatabaseAuthority(common.ResolverBase):
             additional = []
         return defer.succeed((results, authority, additional))
 
-class QuotingBindAuthority(authority.BindAuthority):
+class DelegatingQuotingBindAuthority(authority.BindAuthority):
     """
-    A BindAuthority that (almost) deals with quoting correctly
+    A delegating BindAuthority that (almost) deals with quoting correctly
     
     This will catch double quotes as marking the start or end of a
     quoted phrase, unless the double quote is escaped by a backslash
@@ -194,12 +194,38 @@ class QuotingBindAuthority(authority.BindAuthority):
             L.append(split_line)
         return filter(None, L)
 
+    def _lookup(self, name, cls, type, timeout = None):
+        maybeDelegate = False
+        deferredResult = authority.BindAuthority._lookup(self, name, cls,
+                                                         type, timeout)
+        # If we didn't find an exact match for the name we were seeking,
+        # check if it's within a subdomain we're supposed to delegate to
+        # some other DNS server.
+        while (isinstance(deferredResult.result, failure.Failure)
+               and '.' in name):
+            maybeDelegate = True
+            name = name[name.find('.') + 1 :]
+            deferredResult = authority.BindAuthority._lookup(self, name, cls,
+                                                             dns.NS, timeout)
+        # If we found somewhere to delegate the query to, our _lookup()
+        # for the NS record resulted in it being in the 'results' section.
+        # We need to instead return that information in the 'authority'
+        # section to delegate, and return an empty 'results' section
+        # (because we didn't find the name we were asked about).  We
+        # leave the 'additional' section as we received it because it
+        # may contain A records for the DNS server we're delegating to.
+        if maybeDelegate and not isinstance(deferredResult.result,
+                                            failure.Failure):
+            (nsResults, nsAuthority, nsAdditional) = deferredResult.result
+            deferredResult = defer.succeed(([], nsResults, nsAdditional))
+        return deferredResult
+
 if '__main__' == __name__:
     resolvers = []
     try:
         for zone in config.dns.zone_files:
             for origin in config.dns.domains:
-                r = QuotingBindAuthority(zone)
+                r = DelegatingQuotingBindAuthority(zone)
                 # This sucks, but if I want a generic zone file, I have to
                 # reload the information by hand
                 r.origin = origin