Browse Source

[213] Propagation of config with tests

The propagation from the config handler.
Michal 'vorner' Vaner 13 years ago
parent
commit
3439230170
2 changed files with 125 additions and 1 deletions
  1. 14 1
      src/bin/bind10/bind10_src.py.in
  2. 111 0
      src/bin/bind10/tests/bind10_test.py.in

+ 14 - 1
src/bin/bind10/bind10_src.py.in

@@ -264,13 +264,25 @@ class BoB:
         self.__stopping = False
         self.exitcode = 0
 
+    def __propagate_component_config(self, config):
+        comps = dict(config)
+        # Fill in the core components, so they stay alive
+        for comp in self.__core_components:
+            if comp in comps:
+                raise Exception(comp + " is core component managed by " +
+                                "bind10 boss, do not set it")
+            comps[comp] = self.__core_components[comp]
+        # Update the configuration
+        self._component_configurator.reconfigure(comps)
+
     def config_handler(self, new_config):
         # If this is initial update, don't do anything now, leave it to startup
         if not self.runnable:
             return
         logger.debug(DBG_COMMANDS, BIND10_RECEIVED_NEW_CONFIGURATION,
                      new_config)
-        # TODO: Propagate the config to the configurator
+        if 'components' in new_config:
+            self.__propagate_component_config(new_config['components'])
         answer = isc.config.ccsession.create_answer(0)
         return answer
 
@@ -347,6 +359,7 @@ class BoB:
         logger.info(BIND10_READING_BOSS_CONFIGURATION)
 
         config_data = self.ccs.get_full_config()
+        self.__propagate_component_config(config_data['components'])
         # Propagate the config to the config manager, first reconfigure
 
     def log_starting(self, process, port = None, address = None):

+ 111 - 0
src/bin/bind10/tests/bind10_test.py.in

@@ -218,6 +218,117 @@ class MockBob(BoB):
     def start_ccsession(self, c_channel_env):
         pass
 
+class TestBossComponents(unittest.TestCase):
+    """
+    Test the boss propagates component configuration properly to the
+    component configurator and acts sane.
+    """
+    def setUp(self):
+        self.__param = None
+        self.__called = False
+        self.__compconfig = {
+            'comp': {
+                'kind': 'needed',
+                'process': 'cat'
+            }
+        }
+
+    def __unary_hook(self, param):
+        """
+        A hook function that stores the parameter for later examination.
+        """
+        self.__param = param
+
+    def __nullary_hook(self):
+        """
+        A hook function that notes down it was called.
+        """
+        self.__called = True
+
+    def __check_core(self, config):
+        """
+        A function checking that the config contains parts for the valid
+        core component configuration.
+        """
+        self.assertIsNotNone(config)
+        for component in ['sockcreator', 'msgq', 'cfgmgr']:
+            self.assertTrue(component in config)
+            self.assertEqual(component, config[component]['special'])
+            self.assertEqual('core', config[component]['kind'])
+
+    def __check_extended(self, config):
+        """
+        This checks that the config contains the core and one more component.
+        """
+        self.__check_core(config)
+        self.assertTrue('comp' in config)
+        self.assertEqual('cat', config['comp']['process'])
+        self.assertEqual('needed', config['comp']['kind'])
+        self.assertEqual(4, len(config))
+
+    def test_correct_run(self):
+        """
+        Test the situation when we run in usual scenario, nothing fails,
+        we just start, reconfigure and then stop peacefully.
+        """
+        bob = MockBob()
+        # Start it
+        orig = bob._component_configurator.startup
+        bob._component_configurator.startup = self.__unary_hook
+        bob.start_all_processes()
+        bob._component_configurator.startup = orig
+        self.__check_core(self.__param)
+        self.assertEqual(3, len(self.__param))
+
+        # Reconfigure it
+        self.__param = None
+        orig = bob._component_configurator.reconfigure
+        bob._component_configurator.reconfigure = self.__unary_hook
+        # Otherwise it does not work
+        bob.runnable = True
+        bob.config_handler({'components': self.__compconfig})
+        self.__check_extended(self.__param)
+        currconfig = self.__param
+        # If we reconfigure it, but it does not contain the components part,
+        # nothing is called
+        bob.config_handler({})
+        self.assertEqual(self.__param, currconfig)
+        self.__param = None
+        bob._component_configurator.reconfigure = orig
+        # Check a configuration that messes up the core components is rejected.
+        compconf = dict(self.__compconfig)
+        compconf['msgq'] = { 'process': 'echo' }
+        # Is it OK to raise, or should it catch also and convert to error
+        # answer?
+        self.assertRaises(Exception, bob.config_handler,
+                          {'components': compconf})
+
+        # Stop it
+        orig = bob._component_configurator.shutdown
+        bob._component_configurator.shutdown = self.__nullary_hook
+        self.__called = False
+        # We can't call shutdown, that one relies on the stuff in main
+        bob.stop_all_processes()
+        bob._component_configurator.shutdown = orig
+        self.assertTrue(self.__called)
+
+    def test_init_config(self):
+        """
+        Test initial configuration is loaded.
+        """
+        bob = MockBob()
+        # Start it
+        bob._component_configurator.reconfigure = self.__unary_hook
+        # We need to return the original read_bind10_config
+        bob.read_bind10_config = lambda: BoB.read_bind10_config(bob)
+        # And provide a session to read the data from
+        class CC:
+            pass
+        bob.ccs = CC()
+        bob.ccs.get_full_config = lambda: {'components': self.__compconfig}
+        bob.start_all_processes()
+        self.__check_extended(self.__param)
+
 class TestBossCmd(unittest.TestCase):
     def test_ping(self):
         """