Browse Source

[2020] catch failure of add_remote_xxx and leave a log message about it.

JINMEI Tatuya 13 years ago
parent
commit
27ab58d1ad
3 changed files with 49 additions and 5 deletions
  1. 14 4
      src/bin/ddns/ddns.py.in
  2. 19 0
      src/bin/ddns/ddns_messages.mes
  3. 16 1
      src/bin/ddns/tests/ddns_test.py

+ 14 - 4
src/bin/ddns/ddns.py.in

@@ -179,6 +179,11 @@ class DDNSServer:
             self._cc.get_default_value('zones'))
         self._cc.start()
 
+        # Internal attributes derived from other modules.  They will be
+        # initialized via dd_remote_xxx below and will be kept updated
+        # through their callbacks.  They are defined as 'protected' so tests
+        # can examine them; but they are essentially private to the class.
+        #
         # Datasource client used for handling update requests: when set,
         # should a tuple of RRClass and DataSourceClient.  Constructed and
         # maintained based on auth configuration.
@@ -187,10 +192,15 @@ class DDNSServer:
         self._secondary_zones = None
 
         # Get necessary configurations from remote modules.
-        self._cc.add_remote_config_by_name(AUTH_MODULE_NAME,
-                                           self.__auth_config_handler)
-        self._cc.add_remote_config_by_name(ZONEMGR_MODULE_NAME,
-                                           self.__zonemgr_config_handler)
+        try:
+            mods = [(AUTH_MODULE_NAME, self.__auth_config_handler),
+                    (ZONEMGR_MODULE_NAME, self.__zonemgr_config_handler)]
+            for mod in mods:
+                self._cc.add_remote_config_by_name(mod[0], mod[1])
+        except ModuleCCSessionError as ex:
+            logger.error(DDNS_GET_REMOTE_CONFIG_FAIL, mod[0], ex)
+            raise ex    # propagte it and die for now
+        # This should succeed as long as cfgmgr is up.
         isc.server_common.tsig_keyring.init_keyring(self._cc)
 
         self._shutdown = False

+ 19 - 0
src/bin/ddns/ddns_messages.mes

@@ -198,3 +198,22 @@ b10-ddns was notified of updates to the SQLite3 DB file that b10-auth
 uses for the underlying data source and on which b10-ddns needs to
 make updates.  b10-ddns then updated its internal setup so further
 updates would be made on the new DB.
+
+% DDNS_GET_REMOTE_CONFIG_FAIL failed to get %1 module configuration: %2
+b10-ddns tried to get configuration of some remote modules for its
+operation, but it failed.  The most likely cause of this is that the
+remote module has not fully started up and b10-ddns couldn't get the
+configuration in a timely fashion.  In the current implementation
+b10-ddns considers it a fatal error and terminates; however, as long
+as b10-ddns is configured as a "dispensable" component (which is the
+default), the parent bind10 process will restart it, and getting the
+remote configuration will eventually (and soon) succeed.  This is not
+the optimal behavior, but should be sufficient in practice.  If it
+really causes an operational trouble other than having a few of this
+log messages, please submit a bug report; there can be several ways to
+make it more sophisticated.  Another, less likely reason for having
+this error is because the remote modules are not actually configured
+to run.  If that's the case fixing the configuration should solve the
+problem - either by making sure the remote module will run or by not
+running b10-ddns (without these remote modules b10-ddns is not
+functional, so there's no point in running it in this case).

+ 16 - 1
src/bin/ddns/tests/ddns_test.py

@@ -23,7 +23,7 @@ from isc.cc.session import SessionTimeout, SessionError, ProtocolError
 from isc.datasrc import DataSourceClient
 from isc.config import module_spec_from_file
 from isc.config.config_data import ConfigData
-from isc.config.ccsession import create_answer
+from isc.config.ccsession import create_answer, ModuleCCSessionError
 from isc.server_common.dns_tcp import DNSTCPContext
 import ddns
 import errno
@@ -217,6 +217,8 @@ class MyCCSession(isc.config.ConfigData):
 
         # Attributes to handle (faked) remote configurations
         self.__callbacks = {}   # record callbacks for updates to remote confs
+        self._raise_mods = set()  # set of modules that triggers exception
+                                  # on add_remote.  settable by tests.
         self._auth_config = {}  # faked auth cfg, settable by tests
         self._zonemgr_config = {} # faked zonemgr cfg, settable by tests
 
@@ -235,6 +237,8 @@ class MyCCSession(isc.config.ConfigData):
         return FakeSocket(1)
 
     def add_remote_config_by_name(self, module_name, update_callback=None):
+        if module_name in self._raise_mods:
+            raise ModuleCCSessionError('Failure requesting remote config data')
         if update_callback is not None:
             self.__callbacks[module_name] = update_callback
         if module_name is 'Auth':
@@ -527,6 +531,17 @@ class TestDDNSServer(unittest.TestCase):
         self.assertEqual({(TEST_ZONE_NAME, TEST_RRCLASS)},
                          self.ddns_server._secondary_zones)
 
+    def test_remote_config_fail(self):
+        # If getting config of Auth or Zonemgr fails on construction of
+        # DDNServer, it should result in ModuleCCSessionError.
+        self.__cc_session._raise_mods.add('Auth')
+        self.assertRaises(ModuleCCSessionError, ddns.DDNSServer,
+                          self.__cc_session)
+
+        self.__cc_session._raise_mods = {'Zonemgr'}
+        self.assertRaises(ModuleCCSessionError, ddns.DDNSServer,
+                          self.__cc_session)
+
     def test_shutdown_command(self):
         '''Test whether the shutdown command works'''
         self.assertFalse(self.ddns_server._shutdown)