From: JINMEI Tatuya Date: Mon, 3 Jun 2013 23:14:09 +0000 (-0700) Subject: [2964] use DataSrcClientsMgr to identify the data source for xfr. X-Git-Tag: bind10-1.2.0beta1-release~423^2~16 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=edc1911c2dd4b941d4658aa0e677f4a8ef4ce819;p=thirdparty%2Fkea.git [2964] use DataSrcClientsMgr to identify the data source for xfr. from this point, xfrin stops auto-create a new zone; the admin must explicitly create empty zone using b10-loadzone -e. --- diff --git a/src/bin/xfrin/tests/xfrin_test.py b/src/bin/xfrin/tests/xfrin_test.py index 9de8d8438d..fed36dc55e 100644 --- a/src/bin/xfrin/tests/xfrin_test.py +++ b/src/bin/xfrin/tests/xfrin_test.py @@ -243,6 +243,23 @@ class MockDataSourceClient(): # pretend it just succeeds pass +class MockDataSrcClientsMgr(): + def __init__(self): + # Default faked result of get_client_list, customizable by tests + self.found_datasrc_client_list = self + + # Default faked result of find(), customizable by tests + self.found_datasrc_client = MockDataSourceClient() + + def get_client_list(self, rrclass): + return self.found_datasrc_client_list + + def find(self, zone_name, want_exact_match, want_finder): + """Pretending find method on the object returned by get_clinet_list""" + if issubclass(type(self.found_datasrc_client), Exception): + raise self.found_datasrc_client + return self.found_datasrc_client, None, None + class MockXfrin(Xfrin): # This is a class attribute of a callable object that specifies a non # default behavior triggered in _cc_check_command(). Specific test methods @@ -2447,6 +2464,9 @@ class TestXfrin(unittest.TestCase): # redirect output self.stderr_backup = sys.stderr sys.stderr = open(os.devnull, 'w') + self.__orig_DataSrcClientsMgr = xfrin.DataSrcClientsMgr + xfrin.DataSrcClientsMgr = MockDataSrcClientsMgr + self.xfr = MockXfrin() self.args = {} self.args['zone_name'] = TEST_ZONE_NAME_STR @@ -2457,6 +2477,7 @@ class TestXfrin(unittest.TestCase): self.args['tsig_key'] = '' def tearDown(self): + xfrin.DataSrcClientsMgr = self.__orig_DataSrcClientsMgr self.assertFalse(self.xfr._module_cc.stopped); self.xfr.shutdown() self.assertTrue(self.xfr._module_cc.stopped); @@ -2543,9 +2564,11 @@ class TestXfrin(unittest.TestCase): def test_command_handler_retransfer(self): self.assertEqual(self.xfr.command_handler("retransfer", self.args)['result'][0], 0) - self.assertEqual(self.args['master'], self.xfr.xfrin_started_master_addr) - self.assertEqual(int(self.args['port']), self.xfr.xfrin_started_master_port) - # By default we use AXFR (for now) + self.assertEqual(self.args['master'], + self.xfr.xfrin_started_master_addr) + self.assertEqual(int(self.args['port']), + self.xfr.xfrin_started_master_port) + # retransfer always uses AXFR self.assertEqual(ZoneInfo.REQUEST_IXFR_DISABLED, self.xfr.xfrin_started_request_ixfr) @@ -2650,6 +2673,37 @@ class TestXfrin(unittest.TestCase): # sys.modules is global, so we must recover it sys.modules['pydnspp'] = dns_module + def test_command_handler_retransfer_datasrc_error(self): + # Failure cases due to various errors at the data source (config/data) + # level + + # No data source client list for the RR class + self.xfr._datasrc_clients_mgr.found_datasrc_client_list = None + self.assertEqual(1, self.xfr.command_handler("retransfer", + self.args)['result'][0]) + + # No data source client for the zone name + self.xfr._datasrc_clients_mgr.found_datasrc_client_list = \ + self.xfr._datasrc_clients_mgr # restore the original + self.xfr._datasrc_clients_mgr.found_datasrc_client = None + self.assertEqual(1, self.xfr.command_handler("retransfer", + self.args)['result'][0]) + + # list.find() raises an exception + self.xfr._datasrc_clients_mgr.found_datasrc_client = \ + isc.datasrc.Error('test exception') + self.assertEqual(1, self.xfr.command_handler("retransfer", + self.args)['result'][0]) + + # datasrc.find() raises an exception + class RaisingkDataSourceClient(MockDataSourceClient): + def find_zone(self, zone_name): + raise isc.datasrc.Error('test exception') + self.xfr._datasrc_clients_mgr.found_datasrc_client = \ + RaisingkDataSourceClient() + self.assertEqual(1, self.xfr.command_handler("retransfer", + self.args)['result'][0]) + def test_command_handler_refresh(self): # at this level, refresh is no different than retransfer. # just confirm the successful case with a different family of address. diff --git a/src/bin/xfrin/xfrin.py.in b/src/bin/xfrin/xfrin.py.in index d46e6a67f8..d2522eef2d 100755 --- a/src/bin/xfrin/xfrin.py.in +++ b/src/bin/xfrin/xfrin.py.in @@ -37,6 +37,7 @@ import isc.net.parse from isc.xfrin.diff import Diff from isc.server_common.auth_command import auth_loadzone_command from isc.server_common.tsig_keyring import init_keyring, get_keyring +from isc.server_common.datasrc_clients_mgr import DataSrcClientsMgr, ConfigError from isc.log_messages.xfrin_messages import * from isc.dns import * @@ -1383,6 +1384,8 @@ class Xfrin: self.recorder = XfrinRecorder() self._shutdown_event = threading.Event() self._counters = Counters(SPECFILE_LOCATION) + # This is essentially private, but we allow tests to customize it. + self._datasrc_clients_mgr = DataSrcClientsMgr() # Initial configuration self._cc_setup() @@ -1439,7 +1442,8 @@ class Xfrin: old_max_transfers_in = self._max_transfers_in old_zones = self._zones - self._max_transfers_in = new_config.get("transfers_in") or self._max_transfers_in + self._max_transfers_in = \ + new_config.get("transfers_in") or self._max_transfers_in if 'zones' in new_config: self._clear_zone_info() @@ -1459,7 +1463,7 @@ class Xfrin: self._set_db_file() def _datasrc_config_handler(self, new_config, config_data): - pass + self._datasrc_clients_mgr.reconfigure(new_config) def shutdown(self): ''' shutdown the xfrin process. the thread which is doing xfrin should be @@ -1732,24 +1736,24 @@ class Xfrin: if self.recorder.xfrin_in_progress(zone_name): return (1, 'zone xfrin is in progress') - # Create a data source client used in this XFR session. Right now we - # still assume an sqlite3-based data source, and use both the old and - # new data source APIs. We also need to use a mock client for tests. - # For a temporary workaround to deal with these situations, we skip the - # creation when the given file is none (the test case). Eventually - # this code will be much cleaner. + # Identify the data source to which the zone content is transferred, + # and get the current zone SOA from the data source (if available). datasrc_client = None - if db_file is not None: - # temporary hardcoded sqlite initialization. Once we decide on - # the config specification, we need to update this (TODO) - # this may depend on #1207, or any follow-up ticket created for - # #1207 - datasrc_type = "sqlite3" - datasrc_config = "{ \"database_file\": \"" + db_file + "\"}" - datasrc_client = DataSourceClient(datasrc_type, datasrc_config) - - # Get the current zone SOA (if available). - zone_soa = _get_zone_soa(datasrc_client, zone_name, rrclass) + clist = self._datasrc_clients_mgr.get_client_list(rrclass) + if clist is None: + return (1, 'no data source is configured for class %s' % rrclass) + + try: + datasrc_client = clist.find(zone_name, True, False)[0] + if datasrc_client is None: # can happen, so log it separately. + logger.error(XFRIN_NO_DATASRC, + format_zone_str(zone_name, rrclass)) + return (1, 'no data source for transferring %s' % + format_zone_str(zone_name, rrclass)) + zone_soa = _get_zone_soa(datasrc_client, zone_name, rrclass) + except isc.datasrc.Error as ex: # rare case error, convert (so logged) + raise XfrinException('unexpected failure in datasrc module: ' + + str(ex)) xfrin_thread = threading.Thread(target=process_xfrin, args=(self, self.recorder, @@ -1790,6 +1794,7 @@ def _get_zone_soa(datasrc_client, zone_name, zone_class): """ # datasrc_client should never be None in production case (only tests could # specify None) + # TBD: this CAN NOW BE CLEANED UP if datasrc_client is None: return None diff --git a/src/bin/xfrin/xfrin_messages.mes b/src/bin/xfrin/xfrin_messages.mes index 33a2193db9..011f1e7d59 100644 --- a/src/bin/xfrin/xfrin_messages.mes +++ b/src/bin/xfrin/xfrin_messages.mes @@ -153,6 +153,17 @@ from does not match the master address in the Xfrin configuration. The notify is ignored. This may indicate that the configuration for the master is wrong, that a wrong machine is sending notifies, or that fake notifies are being sent. +% XFRIN_NO_DATASRC no data source for transferring %1 +The xfrin daemon received a command that would trigger a transfer, +but could not find a data source where the specified zone belong. +There can be several reasons for this error: it may be a simple +misspelling in the xfrin or zonemgr configuration, or in the user +supplied parameter if it is triggered by an external command (such as +from bindctl). Another possibility is that this is the initial transfer +for newly setup secondary zone. In this case at least an initial empty zone +must be created in one of configured data sources. This can be done by +the -e option of b10-loadzone. + % XFRIN_RECEIVED_COMMAND received command: %1 The xfrin daemon received a command on the command channel.