Browse Source

[2911] updates to retransfer/refresh so it works with new semantics.

actually refresh wasn't defined in spec, so is defined now.
retransfer is revised so it always uses AXFR (BIND 9 compatible).
lettuce tests are adjusted accordingly.
JINMEI Tatuya 12 years ago
parent
commit
0332ecca45

+ 10 - 8
src/bin/xfrin/tests/xfrin_test.py

@@ -2654,8 +2654,8 @@ class TestXfrin(unittest.TestCase):
                          self.xfr.xfrin_started_master_addr)
                          self.xfr.xfrin_started_master_addr)
         self.assertEqual(int(TEST_MASTER_PORT),
         self.assertEqual(int(TEST_MASTER_PORT),
                          self.xfr.xfrin_started_master_port)
                          self.xfr.xfrin_started_master_port)
-        # By default we use AXFR (for now)
-        self.assertEqual(ZoneInfo.REQUEST_IXFR_DISABLED,
+        # By default we use IXFR (with AXFR fallback)
+        self.assertEqual(ZoneInfo.REQUEST_IXFR_FIRST,
                          self.xfr.xfrin_started_request_ixfr)
                          self.xfr.xfrin_started_request_ixfr)
 
 
     def test_command_handler_notify(self):
     def test_command_handler_notify(self):
@@ -2928,7 +2928,7 @@ class TestXfrin(unittest.TestCase):
 
 
     def common_ixfr_setup(self, xfr_mode, request_ixfr, tsig_key_str=None):
     def common_ixfr_setup(self, xfr_mode, request_ixfr, tsig_key_str=None):
         # This helper method explicitly sets up a zone configuration with
         # This helper method explicitly sets up a zone configuration with
-        # use_ixfr, and invokes either retransfer or refresh.
+        # request_ixfr, and invokes either retransfer or refresh.
         # Shared by some of the following test cases.
         # Shared by some of the following test cases.
         config = {'zones': [
         config = {'zones': [
                 {'name': 'example.com.',
                 {'name': 'example.com.',
@@ -2940,15 +2940,17 @@ class TestXfrin(unittest.TestCase):
                                                   self.args)['result'][0], 0)
                                                   self.args)['result'][0], 0)
 
 
     def test_command_handler_retransfer_ixfr_enabled(self):
     def test_command_handler_retransfer_ixfr_enabled(self):
-        # If IXFR is explicitly enabled in config, IXFR will be used
+        # retransfer always uses AXFR (disabling IXFR), regardless of
+        # request_ixfr value
         self.common_ixfr_setup('retransfer', 'yes')
         self.common_ixfr_setup('retransfer', 'yes')
-        self.assertEqual(ZoneInfo.REQUEST_IXFR_FIRST,
+        self.assertEqual(ZoneInfo.REQUEST_IXFR_DISABLED,
                          self.xfr.xfrin_started_request_ixfr)
                          self.xfr.xfrin_started_request_ixfr)
 
 
     def test_command_handler_refresh_ixfr_enabled(self):
     def test_command_handler_refresh_ixfr_enabled(self):
-        # Same for refresh
-        self.common_ixfr_setup('refresh', 'yes')
-        self.assertEqual(ZoneInfo.REQUEST_IXFR_FIRST,
+        # for refresh, it honors zone configuration if defined (the default
+        # case is covered in test_command_handler_refresh
+        self.common_ixfr_setup('refresh', 'no')
+        self.assertEqual(ZoneInfo.REQUEST_IXFR_DISABLED,
                          self.xfr.xfrin_started_request_ixfr)
                          self.xfr.xfrin_started_request_ixfr)
 
 
     def test_command_handler_retransfer_with_tsig(self):
     def test_command_handler_retransfer_with_tsig(self):

+ 40 - 17
src/bin/xfrin/xfrin.py.in

@@ -1304,6 +1304,12 @@ class ZoneInfo:
     REQUEST_IXFR_ONLY = 1       # request_ixfr=only, use IXFR only
     REQUEST_IXFR_ONLY = 1       # request_ixfr=only, use IXFR only
     REQUEST_IXFR_DISABLED = 2   # request_ixfr=no, AXFR-only
     REQUEST_IXFR_DISABLED = 2   # request_ixfr=no, AXFR-only
 
 
+    # Map from configuration values for request_ixfr to internal values
+    # This is a constant; don't modify.
+    REQUEST_IXFR_CFG_TO_VAL = { 'yes': REQUEST_IXFR_FIRST,
+                                'only': REQUEST_IXFR_ONLY,
+                                'no': REQUEST_IXFR_DISABLED }
+
     def __init__(self, config_data, module_cc):
     def __init__(self, config_data, module_cc):
         """Creates a zone_info with the config data element as
         """Creates a zone_info with the config data element as
            specified by the 'zones' list in xfrin.spec. Module_cc is
            specified by the 'zones' list in xfrin.spec. Module_cc is
@@ -1426,11 +1432,8 @@ class ZoneInfo:
         if request_ixfr is None:
         if request_ixfr is None:
             request_ixfr = \
             request_ixfr = \
                 self._module_cc.get_default_value("zones/request_ixfr")
                 self._module_cc.get_default_value("zones/request_ixfr")
-        cfg_to_val = { 'yes': self.REQUEST_IXFR_FIRST,
-                       'only': self.REQUEST_IXFR_ONLY,
-                       'no': self.REQUEST_IXFR_DISABLED }
         try:
         try:
-            self.__request_ixfr = cfg_to_val[request_ixfr]
+            self.__request_ixfr = self.REQUEST_IXFR_CFG_TO_VAL[request_ixfr]
         except KeyError:
         except KeyError:
             raise XfrinZoneInfoException('invalid value for request_ixfr: ' +
             raise XfrinZoneInfoException('invalid value for request_ixfr: ' +
                                          request_ixfr)
                                          request_ixfr)
@@ -1633,7 +1636,25 @@ class Xfrin:
         # Notified address is okay
         # Notified address is okay
         return None
         return None
 
 
-    def __handle_xfr_command(self, args, arg_db, check_soa, addr_validator):
+    def __get_running_request_ixfr(self, arg_request_ixfr, zone_info):
+        """Determine the request_ixfr policy for a specific transfer.
+
+        This is a dedicated subroutine of __handle_xfr_command.
+
+        """
+        # If explicitly specified, use it.
+        if arg_request_ixfr is not None:
+            return arg_request_ixfr
+        # Otherwise, if zone info is known, use its value.
+        if zone_info is not None:
+            return zone_info.request_ixfr
+        # Otherwise, use the default value for ZoneInfo
+        request_ixfr_def = \
+            self._module_cc.get_default_value("zones/request_ixfr")
+        return ZoneInfo.REQUEST_IXFR_CFG_TO_VAL[request_ixfr_def]
+
+    def __handle_xfr_command(self, args, arg_db, check_soa, addr_validator,
+                             request_ixfr):
         """Common subroutine for handling transfer commands.
         """Common subroutine for handling transfer commands.
 
 
         This helper method unifies both cases of transfer command from
         This helper method unifies both cases of transfer command from
@@ -1657,15 +1678,13 @@ class Xfrin:
         (zone_name, rrclass) = self._parse_zone_name_and_class(args)
         (zone_name, rrclass) = self._parse_zone_name_and_class(args)
         master_addr = self._parse_master_and_port(args, zone_name, rrclass)
         master_addr = self._parse_master_and_port(args, zone_name, rrclass)
         zone_info = self._get_zone_info(zone_name, rrclass)
         zone_info = self._get_zone_info(zone_name, rrclass)
-        request_ixfr = ZoneInfo.REQUEST_IXFR_DISABLED
-        if zone_info is not None:
-            request_ixfr = zone_info.request_ixfr
         tsig_key = None if zone_info is None else zone_info.get_tsig_key()
         tsig_key = None if zone_info is None else zone_info.get_tsig_key()
         db_file = arg_db or self._get_db_file()
         db_file = arg_db or self._get_db_file()
         zone_str = format_zone_str(zone_name, rrclass) # for logging
         zone_str = format_zone_str(zone_name, rrclass) # for logging
         answer = addr_validator(master_addr, zone_str, zone_info)
         answer = addr_validator(master_addr, zone_str, zone_info)
         if answer is not None:
         if answer is not None:
             return answer
             return answer
+        request_ixfr = self.__get_running_request_ixfr(request_ixfr, zone_info)
         ret = self.xfrin_start(zone_name, rrclass, db_file, master_addr,
         ret = self.xfrin_start(zone_name, rrclass, db_file, master_addr,
                                tsig_key, request_ixfr, check_soa)
                                tsig_key, request_ixfr, check_soa)
         return create_answer(ret[0], ret[1])
         return create_answer(ret[0], ret[1])
@@ -1683,16 +1702,20 @@ class Xfrin:
                 addr_validator = \
                 addr_validator = \
                     lambda x, y, z: self.__validate_notify_addr(x, y, z)
                     lambda x, y, z: self.__validate_notify_addr(x, y, z)
                 answer = self.__handle_xfr_command(args, None, True,
                 answer = self.__handle_xfr_command(args, None, True,
-                                                   addr_validator)
-            elif command == 'retransfer' or command == 'refresh':
-                # retransfer/refresh from cmdctl (sent by bindctl).
+                                                   addr_validator, None)
+            elif command == 'retransfer':
+                # retransfer from cmdctl (sent by bindctl).
                 # No need for address validation, db_file may be specified
                 # No need for address validation, db_file may be specified
-                # with the command, and whether to do SOA check depends on
-                # type of command.
-                check_soa = False if command == 'retransfer' else True
-                answer = self.__handle_xfr_command(args, args.get('db_file'),
-                                                   check_soa,
-                                                   lambda x, y, z: None)
+                # with the command, and skip SOA check, always use AXFR.
+                answer = self.__handle_xfr_command(
+                    args, args.get('db_file'), False, lambda x, y, z: None,
+                    ZoneInfo.REQUEST_IXFR_DISABLED)
+            elif command == 'refresh':
+                # retransfer from cmdctl (sent by bindctl).  similar to
+                # retransfer, but do SOA check, and honor request_ixfr config.
+                answer = self.__handle_xfr_command(
+                    args, args.get('db_file'), True, lambda x, y, z: None,
+                    None)
             # return statistics data to the stats daemon
             # return statistics data to the stats daemon
             elif command == "getstats":
             elif command == "getstats":
                 # The log level is here set to debug in order to avoid
                 # The log level is here set to debug in order to avoid

+ 30 - 1
src/bin/xfrin/xfrin.spec

@@ -61,7 +61,36 @@
     "commands": [
     "commands": [
      {
      {
         "command_name": "retransfer",
         "command_name": "retransfer",
-        "command_description": "retransfer a single zone without checking zone serial number",
+        "command_description": "retransfer a single zone without checking zone serial number, always using AXFR",
+        "command_args": [ {
+            "item_name": "zone_name",
+            "item_type": "string",
+            "item_optional": false,
+            "item_default": ""
+          },
+          {
+            "item_name": "zone_class",
+            "item_type": "string",
+            "item_optional": true,
+            "item_default": "IN"
+          },
+          {
+            "item_name": "master",
+            "item_type": "string",
+            "item_optional": true,
+            "item_default": ""
+          },
+          {
+            "item_name": "port",
+            "item_type": "integer",
+            "item_optional": true,
+            "item_default": 53
+          }
+        ]
+      },
+     {
+        "command_name": "refresh",
+        "command_description": "transfer a single zone with checking zone serial number and honoring the request_ixfr policy",
         "command_args": [ {
         "command_args": [ {
             "item_name": "zone_name",
             "item_name": "zone_name",
             "item_type": "string",
             "item_type": "string",

+ 2 - 1
tests/lettuce/configurations/xfrin/retransfer_slave_notify.conf.orig

@@ -28,7 +28,8 @@
         "zones": [ {
         "zones": [ {
             "name": "example.org",
             "name": "example.org",
             "master_addr": "::1",
             "master_addr": "::1",
-            "master_port": 47807
+            "master_port": 47807,
+	    "request_ixfr": "no"
         } ]
         } ]
     },
     },
     "Zonemgr": {
     "Zonemgr": {

+ 2 - 1
tests/lettuce/configurations/xfrin/retransfer_slave_notify_v4.conf

@@ -28,7 +28,8 @@
         "zones": [ {
         "zones": [ {
             "name": "example.org",
             "name": "example.org",
             "master_addr": "127.0.0.1",
             "master_addr": "127.0.0.1",
-            "master_port": 47809
+            "master_port": 47809,
+	    "request_ixfr": "no"
         } ]
         } ]
     },
     },
     "Zonemgr": {
     "Zonemgr": {

+ 2 - 1
tests/lettuce/features/xfrin_bind10.feature

@@ -182,7 +182,8 @@ Feature: Xfrin
     example.    3600    IN      SOA     ns1.example. hostmaster.example. 94 3600 900 7200 300
     example.    3600    IN      SOA     ns1.example. hostmaster.example. 94 3600 900 7200 300
     """
     """
 
 
-    When I send bind10 the command Xfrin retransfer example. IN ::1 47807
+    # To invoke IXFR we need to use refresh command
+    When I send bind10 the command Xfrin refresh example. IN ::1 47807
     Then wait for new bind10 stderr message XFRIN_GOT_INCREMENTAL_RESP
     Then wait for new bind10 stderr message XFRIN_GOT_INCREMENTAL_RESP
     Then wait for new bind10 stderr message XFRIN_IXFR_TRANSFER_SUCCESS not XFRIN_XFR_PROCESS_FAILURE
     Then wait for new bind10 stderr message XFRIN_IXFR_TRANSFER_SUCCESS not XFRIN_XFR_PROCESS_FAILURE
     # This can't be 'wait for new'
     # This can't be 'wait for new'