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
         # next try sending a SIGTERM
         processes_to_stop = list(self.processes.values())
         processes_to_stop = list(self.processes.values())
         for component in processes_to_stop:
         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(),
             logger.info(BIND10_SEND_SIGTERM, component.name(),
                         component.pid())
                         component.pid())
             try:
             try:
@@ -651,12 +654,20 @@ class BoB:
                 # finally exited)
                 # finally exited)
                 pass
                 pass
         # finally, send SIGKILL (unmaskable termination) until everybody dies
         # 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
             # XXX: some delay probably useful... how much is uncertain
             time.sleep(0.1)
             time.sleep(0.1)
             self.reap_children()
             self.reap_children()
             processes_to_stop = list(self.processes.values())
             processes_to_stop = list(self.processes.values())
+            alive = False
             for component in processes_to_stop:
             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(),
                 logger.info(BIND10_SEND_SIGKILL, component.name(),
                             component.pid())
                             component.pid())
                 try:
                 try:

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

@@ -329,6 +329,19 @@ class TestBossComponents(unittest.TestCase):
         bob.start_all_processes()
         bob.start_all_processes()
         self.__check_extended(self.__param)
         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):
 class TestBossCmd(unittest.TestCase):
     def test_ping(self):
     def test_ping(self):
         """
         """

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

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

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

@@ -67,6 +67,23 @@ class BossUtils:
         tm = time.time()
         tm = time.time()
         isc.bind10.component.time.time = lambda: tm + 30
         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):
 class ComponentTests(BossUtils, unittest.TestCase):
     """
     """
     Tests for the bind10.component.Component class
     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']:
         for kind in ['Core', 'CORE', 'nonsense', 'need ed', 'required']:
             self.assertRaises(ValueError, Component, 'No process', self, kind)
             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):
 class TestComponent(Component):
     """
     """
     A test component. It does not start any processes or so, it just logs
     A test component. It does not start any processes or so, it just logs