Browse Source

[1457] rename helpers, add cname update tests

Jelte Jansen 13 years ago
parent
commit
1f66bb6dd4

+ 26 - 19
src/lib/python/isc/ddns/session.py

@@ -58,7 +58,7 @@ class UpdateError(Exception):
         self.rcode = rcode
         self.rcode = rcode
         self.nolog = nolog
         self.nolog = nolog
 
 
-def rrset_as_rrs(rrset, method, *kwargs):
+def foreach_rr_in_rrset(rrset, method, *kwargs):
     '''Helper function. For DDNS, in a number of cases, we need to
     '''Helper function. For DDNS, in a number of cases, we need to
        treat the various RRs in a single RRset separately.
        treat the various RRs in a single RRset separately.
        Our libdns++ has no concept of RRs, so in that case,
        Our libdns++ has no concept of RRs, so in that case,
@@ -76,7 +76,7 @@ def rrset_as_rrs(rrset, method, *kwargs):
        with my_print("foo", rrset)
        with my_print("foo", rrset)
        And with this helper function, to print each rr invidually,
        And with this helper function, to print each rr invidually,
        you'd call
        you'd call
-       rrset_as_rrset(rrset, my_print, "foo", rrset)
+       foreach_rr_in_rrsetet(rrset, my_print, "foo", rrset)
        Note the rrset is needed twice, the first to identify it,
        Note the rrset is needed twice, the first to identify it,
        the second as the 'real' argument to my_print (which is replaced
        the second as the 'real' argument to my_print (which is replaced
        by this function.
        by this function.
@@ -95,11 +95,11 @@ def rrset_as_rrs(rrset, method, *kwargs):
         result = method(*args)
         result = method(*args)
     return result
     return result
 
 
-def rrset_class_conversion(rrset, rrclass):
+def convert_rrset_class(rrset, rrclass):
     '''Returns a (new) rrset with the data from the given rrset,
     '''Returns a (new) rrset with the data from the given rrset,
        but of the given class. Useful to convert from NONE and ANY to
        but of the given class. Useful to convert from NONE and ANY to
        a real class'''
        a real class'''
-    # QUERY, do we want to do this as a special case of the rrset_as_rrs?
+    # QUERY, do we want to do this as a special case of the foreach_rr_in_rrset?
     # or would that make it too complicated?
     # or would that make it too complicated?
     new_rrset = isc.dns.RRset(rrset.get_name(), rrclass, rrset.get_type(),
     new_rrset = isc.dns.RRset(rrset.get_name(), rrclass, rrset.get_type(),
                               rrset.get_ttl())
                               rrset.get_ttl())
@@ -464,7 +464,7 @@ class UpdateSession:
                 if rrset.get_type() == RRType.SOA():
                 if rrset.get_type() == RRType.SOA():
                     # In case there's multiple soa records in the update
                     # In case there's multiple soa records in the update
                     # somehow, just take the last
                     # somehow, just take the last
-                    rrset_as_rrs(rrset, self.__set_soa_rrset, rrset)
+                    foreach_rr_in_rrset(rrset, self.__set_soa_rrset, rrset)
             elif rrset.get_class() == RRClass.ANY():
             elif rrset.get_class() == RRClass.ANY():
                 if rrset.get_ttl().get_value() != 0:
                 if rrset.get_ttl().get_value() != 0:
                     logger.info(LIBDDNS_UPDATE_DELETE_NONZERO_TTL,
                     logger.info(LIBDDNS_UPDATE_DELETE_NONZERO_TTL,
@@ -525,23 +525,30 @@ class UpdateSession:
                                             rrset.get_type(),
                                             rrset.get_type(),
                                             finder.NO_WILDCARD |
                                             finder.NO_WILDCARD |
                                             finder.FIND_GLUE_OK)
                                             finder.FIND_GLUE_OK)
-        if result == finder.SUCCESS:
+        if result == finder.CNAME:
+            if rrset.get_type() != RRType.CNAME():
+                # Ignore non-cname rrs that try to update
+                # CNAME records
+                return
+            else:
+                # remove the original CNAME
+                diff.delete_data(orig_rrset)
+        elif result == finder.SUCCESS:
             # if update is cname, and zone rr is not, ignore
             # if update is cname, and zone rr is not, ignore
             if rrset.get_type() == RRType.CNAME():
             if rrset.get_type() == RRType.CNAME():
-                # can the orig_rrset be of different type?
+                if orig_rrset.get_type() != RRType.CNAME():
-                if orig_rrset.get_type() == RRType.CNAME():
+                    # Ignore CNAME update for non-CNAME data
-                    diff.remove_data(orig_rrset)
-                else:
-                    # ignore
                     return
                     return
-            elif orig_rrset.get_type() == RRType.CNAME():
+                else:
-                # ignore
+                    # Remove original CNAME record (the new one
-                return
+                    # is added below)
+                    diff.delete_data(orig_rrset)
             # We do not have WKS support at this time, but if there
             # We do not have WKS support at this time, but if there
             # are special Update equality rules such as for WKS, and
             # are special Update equality rules such as for WKS, and
             # we do have support for the type, this is where the check
             # we do have support for the type, this is where the check
             # (and potential delete) would go.
             # (and potential delete) would go.
-        rrset_as_rrs(rrset, self.__do_update_add_single_rr, diff, rrset, orig_rrset)
+        print("[XX] UPDATE RRSET: " + str(rrset))
+        foreach_rr_in_rrset(rrset, self.__do_update_add_single_rr, diff, rrset, orig_rrset)
 
 
     def __do_update_delete_rrset(self, datasrc_client, zname, diff, rrset):
     def __do_update_delete_rrset(self, datasrc_client, zname, diff, rrset):
         _, finder = datasrc_client.find_zone(rrset.get_name())
         _, finder = datasrc_client.find_zone(rrset.get_name())
@@ -554,7 +561,7 @@ class UpdateSession:
             to_delete.get_type() == RRType.NS()):
             to_delete.get_type() == RRType.NS()):
             # ignore
             # ignore
             return
             return
-        rrset_as_rrs(to_delete, diff.delete_data, to_delete)
+        foreach_rr_in_rrset(to_delete, diff.delete_data, to_delete)
 
 
     def __ns_deleter_helper(self, datasrc_client, zname, diff, rrset):
     def __ns_deleter_helper(self, datasrc_client, zname, diff, rrset):
         _, finder = datasrc_client.find_zone(rrset.get_name())
         _, finder = datasrc_client.find_zone(rrset.get_name())
@@ -598,7 +605,7 @@ class UpdateSession:
                     to_delete.get_type() == RRType.NS()):
                     to_delete.get_type() == RRType.NS()):
                     continue
                     continue
                 else:
                 else:
-                    rrset_as_rrs(to_delete, diff.delete_data, to_delete)
+                    foreach_rr_in_rrset(to_delete, diff.delete_data, to_delete)
 
 
     def __do_update_delete_rrs_from_rrset(self, datasrc_client, zname, zclass, diff, rrset):
     def __do_update_delete_rrs_from_rrset(self, datasrc_client, zname, zclass, diff, rrset):
         # Delete all rrs in the rrset, except if name=zname and type=soa, or
         # Delete all rrs in the rrset, except if name=zname and type=soa, or
@@ -606,7 +613,7 @@ class UpdateSession:
 
 
         # The delete does not want class NONE, we would not have gotten here
         # The delete does not want class NONE, we would not have gotten here
         # if it wasn't, but now is a good time to change it to the zclass.
         # if it wasn't, but now is a good time to change it to the zclass.
-        to_delete = rrset_class_conversion(rrset, zclass)
+        to_delete = convert_rrset_class(rrset, zclass)
 
 
         if rrset.get_name() == zname:
         if rrset.get_name() == zname:
             if rrset.get_type() == RRType.SOA():
             if rrset.get_type() == RRType.SOA():
@@ -617,7 +624,7 @@ class UpdateSession:
                 # delegate to helper method
                 # delegate to helper method
                 self.__ns_deleter_helper(datasrc_client, zname, diff, to_delete)
                 self.__ns_deleter_helper(datasrc_client, zname, diff, to_delete)
                 return
                 return
-        rrset_as_rrs(to_delete, diff.delete_data, to_delete)
+        foreach_rr_in_rrset(to_delete, diff.delete_data, to_delete)
 
 
     def __update_soa(self, datasrc_client, zname, zclass, diff):
     def __update_soa(self, datasrc_client, zname, zclass, diff):
         # Get the existing SOA
         # Get the existing SOA

+ 56 - 5
src/lib/python/isc/ddns/tests/session_tests.py

@@ -153,10 +153,10 @@ class SessionTest(unittest.TestCase):
         # zone class doesn't match
         # zone class doesn't match
         self.check_notauth(Name('example.org'), RRClass.CH())
         self.check_notauth(Name('example.org'), RRClass.CH())
 
 
-    def rrset_as_rrs_helper(self, rr, l):
+    def foreach_rr_in_rrset_helper(self, rr, l):
         l.append(rr.to_text())
         l.append(rr.to_text())
 
 
-    def test_rrset_as_rrset(self):
+    def test_foreach_rr_in_rrsetet(self):
         rrset = isc.dns.RRset(isc.dns.Name("www.example.org"),
         rrset = isc.dns.RRset(isc.dns.Name("www.example.org"),
                                        TEST_RRCLASS,
                                        TEST_RRCLASS,
                                        isc.dns.RRType.A(),
                                        isc.dns.RRType.A(),
@@ -166,7 +166,7 @@ class SessionTest(unittest.TestCase):
                                                "192.0.2.1"))
                                                "192.0.2.1"))
 
 
         l = []
         l = []
-        rrset_as_rrs(rrset, self.rrset_as_rrs_helper, rrset, l)
+        foreach_rr_in_rrset(rrset, self.foreach_rr_in_rrset_helper, rrset, l)
         self.assertEqual(["www.example.org. 3600 IN A 192.0.2.1\n"], l)
         self.assertEqual(["www.example.org. 3600 IN A 192.0.2.1\n"], l)
 
 
         rrset.add_rdata(isc.dns.Rdata(rrset.get_type(),
         rrset.add_rdata(isc.dns.Rdata(rrset.get_type(),
@@ -180,7 +180,7 @@ class SessionTest(unittest.TestCase):
         # one entry, with a multiline string
         # one entry, with a multiline string
         # but through the helper, there should be several 1-line entries
         # but through the helper, there should be several 1-line entries
         l = []
         l = []
-        self.rrset_as_rrs_helper(rrset, l)
+        self.foreach_rr_in_rrset_helper(rrset, l)
         self.assertEqual(["www.example.org. 3600 IN A 192.0.2.1\n" +
         self.assertEqual(["www.example.org. 3600 IN A 192.0.2.1\n" +
                           "www.example.org. 3600 IN A 192.0.2.2\n" +
                           "www.example.org. 3600 IN A 192.0.2.2\n" +
                           "www.example.org. 3600 IN A 192.0.2.3\n"
                           "www.example.org. 3600 IN A 192.0.2.3\n"
@@ -188,7 +188,7 @@ class SessionTest(unittest.TestCase):
 
 
         # but through the helper, there should be several 1-line entries
         # but through the helper, there should be several 1-line entries
         l = []
         l = []
-        rrset_as_rrs(rrset, self.rrset_as_rrs_helper, rrset, l)
+        foreach_rr_in_rrset(rrset, self.foreach_rr_in_rrset_helper, rrset, l)
         self.assertEqual(["www.example.org. 3600 IN A 192.0.2.1\n",
         self.assertEqual(["www.example.org. 3600 IN A 192.0.2.1\n",
                           "www.example.org. 3600 IN A 192.0.2.2\n",
                           "www.example.org. 3600 IN A 192.0.2.2\n",
                           "www.example.org. 3600 IN A 192.0.2.3\n",
                           "www.example.org. 3600 IN A 192.0.2.3\n",
@@ -1124,6 +1124,57 @@ class SessionTest(unittest.TestCase):
                                isc.dns.RRType.NS(),
                                isc.dns.RRType.NS(),
                                short_ns_rrset)
                                short_ns_rrset)
 
 
+    def test_update_apex_special_cases(self):
+        self.initialize_update_rrsets()
+
+        # The original cname, for checking
+        orig_cname_rrset = isc.dns.RRset(isc.dns.Name("cname.example.org"),
+                              TEST_RRCLASS,
+                              isc.dns.RRType.CNAME(),
+                              isc.dns.RRTTL(3600))
+        orig_cname_rrset.add_rdata(isc.dns.Rdata(orig_cname_rrset.get_type(),
+                                      orig_cname_rrset.get_class(),
+                                      "www.example.org."))
+        # The CNAME we will change it to
+        new_cname_rrset = isc.dns.RRset(isc.dns.Name("cname.example.org"),
+                              TEST_RRCLASS,
+                              isc.dns.RRType.CNAME(),
+                              isc.dns.RRTTL(3600))
+        new_cname_rrset.add_rdata(isc.dns.Rdata(new_cname_rrset.get_type(),
+                                      new_cname_rrset.get_class(),
+                                      "mail.example.org."))
+
+        # Sanity check
+        self.check_inzone_data(isc.datasrc.ZoneFinder.CNAME,
+                               isc.dns.Name("cname.example.org"),
+                               isc.dns.RRType.A(),
+                               orig_cname_rrset)
+
+        # If we try to add data where a cname is preset
+        rrset = isc.dns.RRset(isc.dns.Name("cname.example.org"),
+                              TEST_RRCLASS,
+                              isc.dns.RRType.A(),
+                              isc.dns.RRTTL(3600))
+        rrset.add_rdata(isc.dns.Rdata(rrset.get_type(),
+                                      rrset.get_class(),
+                                      "192.0.2.1"))
+
+        self.check_full_handle_result(Rcode.NOERROR(), [ rrset ])
+        self.check_inzone_data(isc.datasrc.ZoneFinder.CNAME,
+                               isc.dns.Name("cname.example.org"),
+                               isc.dns.RRType.A(),
+                               orig_cname_rrset)
+
+        # But updating the cname itself should work
+        self.check_full_handle_result(Rcode.NOERROR(), [ new_cname_rrset ])
+        self.check_inzone_data(isc.datasrc.ZoneFinder.CNAME,
+                               isc.dns.Name("cname.example.org"),
+                               isc.dns.RRType.A(),
+                               new_cname_rrset)
+        
+        # Likewise, adding a cname where other data is
+        # present should do nothing either
+
 
 
 if __name__ == "__main__":
 if __name__ == "__main__":
     isc.log.init("bind10")
     isc.log.init("bind10")

BIN
src/lib/testutils/testdata/rwtest.sqlite3