Browse Source

[213] Don't kill components that no longer run

Michal 'vorner' Vaner 13 years ago
parent
commit
439b8e22a0

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

@@ -642,6 +642,9 @@ class BoB:
         # next try sending a SIGTERM
         processes_to_stop = list(self.processes.values())
         for component in processes_to_stop:
+            if component.pid() is None:
+                # This isn't running any more for some reason
+                continue
             logger.info(BIND10_SEND_SIGTERM, component.name(),
                         component.pid())
             try:
@@ -651,12 +654,20 @@ class BoB:
                 # finally exited)
                 pass
         # finally, send SIGKILL (unmaskable termination) until everybody dies
-        while self.processes:
+        alive = self.processes # Is there any process alive?
+        # We set alive to false at the start of each killing and reset it
+        # to true whenever we find a component that still lives.
+        while alive:
             # XXX: some delay probably useful... how much is uncertain
             time.sleep(0.1)
             self.reap_children()
             processes_to_stop = list(self.processes.values())
+            alive = False
             for component in processes_to_stop:
+                if component.pid() is None:
+                    # This isn't running any more for some reason
+                    continue
+                alive = True
                 logger.info(BIND10_SEND_SIGKILL, component.name(),
                             component.pid())
                 try:

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

@@ -329,6 +329,19 @@ class TestBossComponents(unittest.TestCase):
         bob.start_all_processes()
         self.__check_extended(self.__param)
 
+    def test_shutdown_no_pid(self):
+        """
+        Test the boss doesn't fail when ve don't have a PID of a component
+        (which means it's not running).
+        """
+        bob = MockBob()
+        class NoComponent:
+            def pid(self):
+                return None
+        bob.processes = {}
+        bob.register_process(1, NoComponent())
+        bob.shutdown()
+
 class TestBossCmd(unittest.TestCase):
     def test_ping(self):
         """

+ 14 - 7
src/lib/python/isc/bind10/component.py

@@ -79,6 +79,7 @@ class Component:
         self._start_func = None
         self._address = address
         self._params = params
+        self._procinfo = None
 
     def start(self):
         """
@@ -199,8 +200,10 @@ class Component:
         Provides a PID of a process, if the component is real running process.
         This implementation expects it to be a real process, but derived class
         may return None in case the component is something else.
+
+        This returns None in case it is not yet running.
         """
-        return self._procinfo.pid
+        return self._procinfo.pid if self._procinfo else None
 
 # These are specialized components. Some of them are components which need
 # special care (like the message queue or socket creator) or they need
@@ -212,6 +215,10 @@ class SockCreator(Component):
     The socket creator component. Will start and stop the socket creator
     accordingly.
     """
+    def __init__(self, process, boss, kind, address=None, params=None):
+        Component.__init__(self, process, boss, kind)
+        self.__creator = None
+
     def start_internal(self):
         self._boss.curproc = 'b10-sockcreator'
         self.__creator = isc.bind10.sockcreator.Creator(LIBEXECDIR + ':' +
@@ -229,14 +236,14 @@ class SockCreator(Component):
         Pid of the socket creator. It is provided differently from a usual
         component.
         """
-        return self.__creator.pid()
+        return self.__creator.pid() if self.__creator else None
 
 class Msgq(Component):
     """
     The message queue. Starting is passed to boss, stopping is not supported
     and we leave the boss kill it by signal.
     """
-    def __init__(self, process, boss, kind, address, params):
+    def __init__(self, process, boss, kind, address=None, params=None):
         Component.__init__(self, process, boss, kind)
         self._start_func = boss.start_msgq
 
@@ -244,25 +251,25 @@ class Msgq(Component):
         pass # Wait for the boss to actually kill it. There's no stop command.
 
 class CfgMgr(Component):
-    def __init__(self, process, boss, kind, address, params):
+    def __init__(self, process, boss, kind, address=None, params=None):
         Component.__init__(self, process, boss, kind)
         self._start_func = boss.start_cfgmgr
         self._address = 'ConfigManager'
 
 class Auth(Component):
-    def __init__(self, process, boss, kind, address, params):
+    def __init__(self, process, boss, kind, address=None, params=None):
         Component.__init__(self, process, boss, kind)
         self._start_func = boss.start_auth
         self._address = 'Auth'
 
 class Resolver(Component):
-    def __init__(self, process, boss, kind, address, params):
+    def __init__(self, process, boss, kind, address=None, params=None):
         Component.__init__(self, process, boss, kind)
         self._start_func = boss.start_resolver
         self._address = 'Resolver'
 
 class CmdCtl(Component):
-    def __init__(self, process, boss, kind, address, params):
+    def __init__(self, process, boss, kind, address=None, params=None):
         Component.__init__(self, process, boss, kind)
         self._start_func = boss.start_cmdctl
         self._address = 'Cmdctl'

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

@@ -67,6 +67,23 @@ class BossUtils:
         tm = time.time()
         isc.bind10.component.time.time = lambda: tm + 30
 
+    # Few functions that pretend to start something. Part of pretending of
+    # being boss.
+    def start_msgq(self):
+        pass
+
+    def start_cfgmgr(self):
+        pass
+
+    def start_auth(self):
+        pass
+
+    def start_resolver(self):
+        pass
+
+    def start_cmdctl(self):
+        pass
+
 class ComponentTests(BossUtils, unittest.TestCase):
     """
     Tests for the bind10.component.Component class
@@ -388,6 +405,20 @@ class ComponentTests(BossUtils, unittest.TestCase):
         for kind in ['Core', 'CORE', 'nonsense', 'need ed', 'required']:
             self.assertRaises(ValueError, Component, 'No process', self, kind)
 
+    def test_pid_not_running(self):
+        """
+        Test that a componet that is not yet started doesn't have a PID.
+        But it won't failed if asked for and returns None.
+        """
+        for component_type in [Component, isc.bind10.component.SockCreator,
+                               isc.bind10.component.Msgq,
+                               isc.bind10.component.CfgMgr,
+                               isc.bind10.component.Auth,
+                               isc.bind10.component.Resolver,
+                               isc.bind10.component.CmdCtl]:
+            component = component_type('none', self, 'needed')
+            self.assertIsNone(component.pid())
+
 class TestComponent(Component):
     """
     A test component. It does not start any processes or so, it just logs