Browse Source

[1514] This ticket implements serial number incrementally update in DDNS module.
This ticket is based on the snapshot of trac1457

haikuo zhang 13 years ago
parent
commit
db1b2905e9
2 changed files with 117 additions and 5 deletions
  1. 45 2
      src/lib/python/isc/ddns/session.py
  2. 72 3
      src/lib/python/isc/ddns/tests/session_tests.py

+ 45 - 2
src/lib/python/isc/ddns/session.py

@@ -112,6 +112,45 @@ def convert_rrset_class(rrset, rrclass):
         new_rrset.add_rdata(isc.dns.Rdata(rrset.get_type(), rrclass, wire))
         new_rrset.add_rdata(isc.dns.Rdata(rrset.get_type(), rrclass, wire))
     return new_rrset
     return new_rrset
 
 
+class DDNSSOA:
+    '''Class to handle the SOA in the DNS update '''
+
+    def __get_serial_internal(self, origin_soa):
+        '''get serial number from soa'''
+        return Serial(int(origin_soa.get_rdata()[0].to_text().split()[2]))
+
+    def __write_soa_internal(self, origin_soa, soa_num):
+        '''write serial number to soa'''
+        new_soa = RRset(origin_soa.get_name(), origin_soa.get_class(),
+                        RRType.SOA(), origin_soa.get_ttl())
+        new_content = ""
+        index = 0
+        for i in origin_soa.get_rdata()[0].to_text().split():
+            if(index == 2):
+                # the second item is serial number
+                new_content = "%s %d"%(new_content, soa_num.get_value())
+            else:
+                new_content = "%s %s"%(new_content, i)
+            index += 1
+        new_soa.add_rdata(Rdata(origin_soa.get_type(), origin_soa.get_class(),
+                                new_content))
+        return new_soa
+
+    def soa_update_check(self, origin_soa, new_soa):
+        old_serial = self.__get_serial_internal(origin_soa)
+        new_serial = self.__get_serial_internal(new_soa)
+        if(new_serial >= old_serial):
+            return True
+        else:
+            return False
+
+    def update_soa(self, origin_soa, inc_number = 1):
+        soa_num = self.__get_serial_internal(origin_soa)
+        soa_num = soa_num + inc_number
+        if soa_num.get_value() == 0:
+            soa_num = soa_num + 1
+        return self.__write_soa_internal(origin_soa, soa_num)
+
 class UpdateSession:
 class UpdateSession:
     '''Protocol handling for a single dynamic update request.
     '''Protocol handling for a single dynamic update request.
 
 
@@ -677,13 +716,17 @@ class UpdateSession:
         result, old_soa, _ = self.__finder.find(self.__zname, RRType.SOA(),
         result, old_soa, _ = self.__finder.find(self.__zname, RRType.SOA(),
                                                 ZoneFinder.NO_WILDCARD |
                                                 ZoneFinder.NO_WILDCARD |
                                                 ZoneFinder.FIND_GLUE_OK)
                                                 ZoneFinder.FIND_GLUE_OK)
-
+        serial_operation = DDNSSOA()
         if self.__added_soa is not None:
         if self.__added_soa is not None:
-            new_soa = self.__added_soa
             # serial check goes here
             # serial check goes here
+            if serial_operation.soa_update_check(old_soa, self.__added_soa):
+                new_soa = self.__added_soa
+            else:
+                pass
         else:
         else:
             new_soa = old_soa
             new_soa = old_soa
             # increment goes here
             # increment goes here
+            new_soa = serial_operation.update_soa(new_soa)
 
 
         diff.delete_data(old_soa)
         diff.delete_data(old_soa)
         diff.add_data(new_soa)
         diff.add_data(new_soa)

+ 72 - 3
src/lib/python/isc/ddns/tests/session_tests.py

@@ -89,6 +89,66 @@ def add_rdata(rrset, rdata):
                                   rrset.get_class(),
                                   rrset.get_class(),
                                   rdata))
                                   rdata))
 
 
+class TestDDNSSOA(unittest.TestCase):
+    '''unittest for the DDNSSOA'''
+    def test_update_soa(self):
+        '''unittest for update_soa function'''
+        soa_update = DDNSSOA()
+        soa_rr = create_rrset("example.org", TEST_RRCLASS,
+                              RRType.SOA(), 3600, ["ns1.example.org. " +
+                              "admin.example.org. " +
+                              "1233 3600 1800 2419200 7200"])
+        expected_soa_rr = create_rrset("example.org", TEST_RRCLASS,
+                                       RRType.SOA(), 3600, ["ns1.example.org. "
+                                       + "admin.example.org. " +
+                                       "1234 3600 1800 2419200 7200"])
+        self.assertEqual(soa_update.update_soa(soa_rr).get_rdata()[0].to_text(),
+                         expected_soa_rr.get_rdata()[0].to_text())
+        max_serial = 2 ** 32 - 1
+        soa_rdata = "%d %s"%(max_serial,"3600 1800 2419200 7200")
+        soa_rr = create_rrset("example.org", TEST_RRCLASS, RRType.SOA(), 3600,
+                              ["ns1.example.org. " + "admin.example.org. " +
+                              soa_rdata])
+        expected_soa_rr = create_rrset("example.org", TEST_RRCLASS,
+                                       RRType.SOA(), 3600, ["ns1.example.org. "
+                                       + "admin.example.org. " +
+                                       "1 3600 1800 2419200 7200"])
+        self.assertEqual(soa_update.update_soa(soa_rr).get_rdata()[0].to_text(),
+                         expected_soa_rr.get_rdata()[0].to_text())
+
+    def test_soa_update_check(self):
+        '''unittest for soa_update_check function'''
+        small_soa_rr = create_rrset("example.org", TEST_RRCLASS, RRType.SOA(),
+                                    3600, ["ns1.example.org. " +
+                                    "admin.example.org. " +
+                                    "1233 3600 1800 2419200 7200"])
+        large_soa_rr = create_rrset("example.org", TEST_RRCLASS, RRType.SOA(),
+                                    3600, ["ns1.example.org. " +
+                                    "admin.example.org. " +
+                                    "1234 3600 1800 2419200 7200"])
+        soa_update = DDNSSOA()
+        # The case of (i1 < i2 and i2 - i1 < 2^(SERIAL_BITS - 1)) in rfc 1982
+        self.assertTrue(soa_update.soa_update_check(small_soa_rr,
+                                                    large_soa_rr))
+        self.assertFalse(soa_update.soa_update_check(large_soa_rr,
+                                                     small_soa_rr))
+        small_serial = 1235 + 2 ** 31
+        soa_rdata = "%d %s"%(small_serial,"3600 1800 2419200 7200")
+        small_soa_rr = create_rrset("example.org", TEST_RRCLASS, RRType.SOA(),
+                                    3600, ["ns1.example.org. " +
+                                           "admin.example.org. " +
+                                           soa_rdata])
+        large_soa_rr = create_rrset("example.org", TEST_RRCLASS, RRType.SOA(),
+                                    3600, ["ns1.example.org. " +
+                                    "admin.example.org. " +
+                                    "1234 3600 1800 2419200 7200"])
+        # The case of (i1 > i2 and i1 - i2 > 2^(SERIAL_BITS - 1)) in rfc 1982
+        self.assertTrue(soa_update.soa_update_check(small_soa_rr,
+                                                    large_soa_rr))
+        self.assertFalse(soa_update.soa_update_check(large_soa_rr,
+                                                     small_soa_rr))
+
+
 class SessionTest(unittest.TestCase):
 class SessionTest(unittest.TestCase):
     '''Session tests'''
     '''Session tests'''
     def setUp(self):
     def setUp(self):
@@ -946,6 +1006,15 @@ class SessionTest(unittest.TestCase):
                                       [ "ns1.example.org. " +
                                       [ "ns1.example.org. " +
                                         "admin.example.org. " +
                                         "admin.example.org. " +
                                         "1234 3600 1800 2419200 7200" ])
                                         "1234 3600 1800 2419200 7200" ])
+        # At some point, the SOA SERIAL will be auto-incremented
+        incremented_soa_rrset_01 = create_rrset("example.org", TEST_RRCLASS,
+                RRType.SOA(), 3600, ["ns1.example.org. " +
+                                     "admin.example.org. " +
+                                     "1235 3600 1800 2419200 7200" ])
+        incremented_soa_rrset_02 = create_rrset("example.org", TEST_RRCLASS,
+                RRType.SOA(), 3600, ["ns1.example.org. " +
+                                     "admin.example.org. " +
+                                     "1236 3600 1800 2419200 7200" ])
 
 
         # We will delete some of the NS records
         # We will delete some of the NS records
         orig_ns_rrset = create_rrset("example.org", TEST_RRCLASS,
         orig_ns_rrset = create_rrset("example.org", TEST_RRCLASS,
@@ -978,16 +1047,16 @@ class SessionTest(unittest.TestCase):
         self.check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
         self.check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
                                isc.dns.Name("example.org"),
                                isc.dns.Name("example.org"),
                                RRType.SOA(),
                                RRType.SOA(),
-                               orig_soa_rrset)
+                               incremented_soa_rrset_01)
 
 
         # If we delete everything at the apex, the SOA and NS rrsets should be
         # If we delete everything at the apex, the SOA and NS rrsets should be
-        # untouched
+        # untouched (but serial will be incremented)
         self.check_full_handle_result(Rcode.NOERROR(),
         self.check_full_handle_result(Rcode.NOERROR(),
                                       [ self.rrset_update_del_name_apex ])
                                       [ self.rrset_update_del_name_apex ])
         self.check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
         self.check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
                                isc.dns.Name("example.org"),
                                isc.dns.Name("example.org"),
                                RRType.SOA(),
                                RRType.SOA(),
-                               orig_soa_rrset)
+                               incremented_soa_rrset_02)
         self.check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
         self.check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
                                isc.dns.Name("example.org"),
                                isc.dns.Name("example.org"),
                                RRType.NS(),
                                RRType.NS(),