Browse Source

[213] Failures of needed components

Michal 'vorner' Vaner 13 years ago
parent
commit
236b6ec7a8

+ 8 - 1
src/lib/python/isc/bind10/component.py

@@ -76,6 +76,7 @@ class Component:
             raise ValueError("Can't start already running component")
         self.start_internal()
         self.__running = True
+        self.__start_time = time.time()
 
     def start_internal(self):
         """
@@ -114,9 +115,15 @@ class Component:
         """
         self.failed_internal()
         self.__running = False
-        if self.__kind == 'core':
+        # If it is a core component or the needed component failed to start
+        # (including it stopped really soon)
+        if self.__kind == 'core' or \
+            (self.__kind == 'needed' and time.time() - 10 < self.__start_time):
             self.__dead = True
             self.__boss.shutdown(1)
+        # This means we want to restart
+        else:
+            self.start()
 
     def failed_internal(self):
         """

+ 51 - 0
src/lib/python/isc/bind10/tests/component_test.py

@@ -128,6 +128,26 @@ class ComponentTests(unittest.TestCase):
         # Nor started
         self.assertRaises(ValueError, component.start)
 
+    def check_restarted(self, component):
+        """
+        Check the component restarted successfully.
+
+        Currently, it is implemented as starting it again right away. This will
+        change, it will register itself into the restart schedule in boss. But
+        as the integration with boss is not clear yet, we don't know how
+        exactly that will happen.
+
+        Reset the self.__start_called to False before calling the function when
+        the component should fail.
+        """
+        self.assertFalse(self.__shutdown)
+        self.assertTrue(self.__start_called)
+        self.assertFalse(self.__stop_called)
+        self.assertTrue(self.__failed_called)
+        self.assertTrue(component.running())
+        # Check it can't be started again
+        self.assertRaises(ValueError, component.start)
+
     def do_start_stop(self, kind):
         """
         This is a body of a test. It creates a componend of given kind,
@@ -203,6 +223,37 @@ class ComponentTests(unittest.TestCase):
         # Check the component is still dead
         self.check_dead(component)
 
+    def test_start_fail_needed(self):
+        """
+        Start and then fail a needed component. As this happens really soon after
+        being started, it is considered failure to start and should bring down the
+        whole server.
+        """
+        # Just ordinary startup
+        component = self.create_component('needed')
+        self.check_startup(component)
+        component.start()
+        self.check_started(component)
+        # Make it fail right away.
+        component.failed()
+        self.check_dead(component)
+
+    def test_start_fail_needed_later(self):
+        """
+        Start and then fail a needed component. But the failure is later on, so
+        we just restart it and will be happy.
+        """
+        # Just ordinary startup
+        component = self.create_component('needed')
+        self.check_startup(component)
+        component.start()
+        self.check_started(component)
+        # Make it fail later on
+        self.__start_called = False
+        self.timeskip()
+        component.failed()
+        self.check_restarted(component)
+
 if __name__ == '__main__':
     isc.log.init("bind10") # FIXME Should this be needed?
     isc.log.resetUnitTestRootLogger()