Browse Source

[trac810] Call checkers with virtual modules

Michal 'vorner' Vaner 14 years ago
parent
commit
111334856c
2 changed files with 57 additions and 10 deletions
  1. 22 10
      src/lib/python/isc/config/cfgmgr.py
  2. 35 0
      src/lib/python/isc/config/tests/cfgmgr_test.py

+ 22 - 10
src/lib/python/isc/config/cfgmgr.py

@@ -312,24 +312,36 @@ class ConfigManager:
         # todo: use api (and check the data against the definition?)
         # todo: use api (and check the data against the definition?)
         old_data = copy.deepcopy(self.config.data)
         old_data = copy.deepcopy(self.config.data)
         conf_part = data.find_no_exc(self.config.data, module_name)
         conf_part = data.find_no_exc(self.config.data, module_name)
+        update_cmd = None
+        use_part = None
         if conf_part:
         if conf_part:
             data.merge(conf_part, cmd)
             data.merge(conf_part, cmd)
-            update_cmd = ccsession.create_command(ccsession.COMMAND_CONFIG_UPDATE,
-                                                  conf_part)
-            seq = self.cc.group_sendmsg(update_cmd, module_name)
-            try:
-                answer, env = self.cc.group_recvmsg(False, seq)
-            except isc.cc.SessionTimeout:
-                answer = ccsession.create_answer(1, "Timeout waiting for answer from " + module_name)
+            use_part = conf_part
         else:
         else:
             conf_part = data.set(self.config.data, module_name, {})
             conf_part = data.set(self.config.data, module_name, {})
             data.merge(conf_part[module_name], cmd)
             data.merge(conf_part[module_name], cmd)
+            use_part = conf_part[module_name]
+
+        if module_name in self.virtual_modules:
+            # The module is virtual, so call it to get the answer
+            try:
+                error = self.virtual_modules[module_name](use_part)
+                if error is None:
+                    answer = ccsession.create_answer(0)
+                else:
+                    answer = ccsession.create_answer(1, error)
+            # Make sure just a validating plugin don't kill the whole manager
+            except Exception as excp:
+                # Provide answer
+                answer = ccsession.create_answer(1, "Exception: " + str(excp))
+        else:
+            # Real module, send it over the wire to it
             # send out changed info
             # send out changed info
-            update_cmd = ccsession.create_command(ccsession.COMMAND_CONFIG_UPDATE,
-                                                  conf_part[module_name])
+            update_cmd = ccsession.create_command(
+                ccsession.COMMAND_CONFIG_UPDATE, use_part)
             seq = self.cc.group_sendmsg(update_cmd, module_name)
             seq = self.cc.group_sendmsg(update_cmd, module_name)
-            # replace 'our' answer with that of the module
             try:
             try:
+                # replace 'our' answer with that of the module
                 answer, env = self.cc.group_recvmsg(False, seq)
                 answer, env = self.cc.group_recvmsg(False, seq)
             except isc.cc.SessionTimeout:
             except isc.cc.SessionTimeout:
                 answer = ccsession.create_answer(1, "Timeout waiting for answer from " + module_name)
                 answer = ccsession.create_answer(1, "Timeout waiting for answer from " + module_name)

+ 35 - 0
src/lib/python/isc/config/tests/cfgmgr_test.py

@@ -338,6 +338,41 @@ class TestConfigManager(unittest.TestCase):
                                 },
                                 },
                                 {'result': [0]})
                                 {'result': [0]})
 
 
+    def test_set_config_virtual(self):
+        """Test that if the module is virtual, we don't send it over the
+           message bus, but call the checking function.
+           """
+        # We run the same three times, with different return values
+        def single_test(value, returnFunc, expectedResult):
+            # Because closures can't assign to closed-in variables, we pass
+            # it trough self
+            self.called_with = None
+            def check_test(new_data):
+                self.called_with = new_data
+                return returnFunc()
+
+            # Register our virtual module
+            self.cm.set_virtual_module(self.spec, check_test)
+            # The fake session will throw now if it is touched, as there's no
+            # message or answer ready. Handy, we don't need any code about it
+            # to check explicitly.
+            result = self.cm._handle_set_config_module(self.spec.
+                                                       get_module_name(),
+                                                       {'item1': value})
+            # Check the correct result is passed and our function was called
+            # With correct data
+            self.assertEqual(self.called_with['item1'], value)
+            self.assertEqual(result, {'result': expectedResult})
+
+        # Success
+        single_test(5, lambda: None, [0])
+        # Graceful error
+        single_test(6, lambda: "Just error", [1, "Just error"])
+        # Exception from the checker
+        def raiser():
+            raise Exception("Just exception")
+        single_test(7, raiser, [1, "Exception: Just exception"])
+
     def test_set_config_all(self):
     def test_set_config_all(self):
         my_ok_answer = { 'result': [ 0 ] }
         my_ok_answer = { 'result': [ 0 ] }