Browse Source

Implement "--brittle" option.

Shane Kerr 14 years ago
parent
commit
3ceeab28d4
2 changed files with 48 additions and 4 deletions
  1. 12 4
      src/bin/bind10/bind10.py.in
  2. 36 0
      src/bin/bind10/tests/bind10_test.py.in

+ 12 - 4
src/bin/bind10/bind10.py.in

@@ -202,7 +202,7 @@ class BoB:
     
     def __init__(self, msgq_socket_file=None, data_path=None,
     config_filename=None, nocache=False, verbose=False, setuid=None,
-    username=None, cmdctl_port=None):
+    username=None, cmdctl_port=None, brittle=False):
         """
             Initialize the Boss of BIND. This is a singleton (only one can run).
         
@@ -235,6 +235,7 @@ class BoB:
         self.data_path = data_path
         self.config_filename = config_filename
         self.cmdctl_port = cmdctl_port
+        self.brittle = brittle
 
     def config_handler(self, new_config):
         # If this is initial update, don't do anything now, leave it to startup
@@ -710,20 +711,22 @@ class BoB:
         if self.verbose:
             sys.stdout.write("[bind10] All processes ended, server done.\n")
 
+    def _get_process_exit_status(self):
+        return os.waitpid(-1, os.WNOHANG)
+
     def reap_children(self):
         """Check to see if any of our child processes have exited, 
         and note this for later handling. 
         """
         while True:
             try:
-                (pid, exit_status) = os.waitpid(-1, os.WNOHANG)
+                (pid, exit_status) = self._get_process_exit_status()
             except OSError as o:
                 if o.errno == errno.ECHILD: break
                 # XXX: should be impossible to get any other error here
                 raise
             if pid == 0: break
             if pid in self.processes:
-
                 # One of the processes we know about.  Get information on it.
                 proc_info = self.processes.pop(pid)
                 proc_info.restart_schedule.set_run_stop_time()
@@ -747,6 +750,11 @@ class BoB:
                         sys.stdout.write(
                                  "[bind10] The b10-msgq process died, shutting down.\n")
                         self.runnable = False
+
+                # If we're in 'brittle' mode, we want to shutdown after
+                # any process dies.
+                if self.brittle:
+                    self.runnable = False
             else:
                 sys.stdout.write("[bind10] Unknown child pid %d exited.\n" % pid)
 
@@ -961,7 +969,7 @@ def main():
     # Go bob!
     boss_of_bind = BoB(options.msgq_socket_file, options.data_path,
                        options.config_file, options.nocache, options.verbose,
-                       setuid, username, options.cmdctl_port)
+                       setuid, username, options.cmdctl_port, options.brittle)
     startup_result = boss_of_bind.startup()
     if startup_result:
         sys.stderr.write("[bind10] Error on startup: %s\n" % startup_result)

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

@@ -156,42 +156,52 @@ class MockBob(BoB):
     def start_msgq(self, c_channel_env):
         self.msgq = True
         self.processes[2] = ProcessInfo('b10-msgq', ['/bin/false'])
+        self.processes[2].pid = 2
 
     def start_cfgmgr(self, c_channel_env):
         self.cfgmgr = True
         self.processes[3] = ProcessInfo('b10-cfgmgr', ['/bin/false'])
+        self.processes[3].pid = 3
 
     def start_ccsession(self, c_channel_env):
         self.ccsession = True
         self.processes[4] = ProcessInfo('b10-ccsession', ['/bin/false'])
+        self.processes[4].pid = 4
 
     def start_auth(self, c_channel_env):
         self.auth = True
         self.processes[5] = ProcessInfo('b10-auth', ['/bin/false'])
+        self.processes[5].pid = 5
 
     def start_resolver(self, c_channel_env):
         self.resolver = True
         self.processes[6] = ProcessInfo('b10-resolver', ['/bin/false'])
+        self.processes[6].pid = 6
 
     def start_xfrout(self, c_channel_env):
         self.xfrout = True
         self.processes[7] = ProcessInfo('b10-xfrout', ['/bin/false'])
+        self.processes[7].pid = 7
 
     def start_xfrin(self, c_channel_env):
         self.xfrin = True
         self.processes[8] = ProcessInfo('b10-xfrin', ['/bin/false'])
+        self.processes[8].pid = 8
 
     def start_zonemgr(self, c_channel_env):
         self.zonemgr = True
         self.processes[9] = ProcessInfo('b10-zonemgr', ['/bin/false'])
+        self.processes[9].pid = 9
 
     def start_stats(self, c_channel_env):
         self.stats = True
         self.processes[10] = ProcessInfo('b10-stats', ['/bin/false'])
+        self.processes[10].pid = 10
 
     def start_cmdctl(self, c_channel_env):
         self.cmdctl = True
         self.processes[11] = ProcessInfo('b10-cmdctl', ['/bin/false'])
+        self.processes[11].pid = 11
 
     # We don't really use all of these stop_ methods. But it might turn out
     # someone would add some stop_ method to BoB and we want that one overriden
@@ -606,5 +616,31 @@ class TestPIDFile(unittest.TestCase):
         self.assertRaises(IOError, dump_pid,
                           'nonexistent_dir' + os.sep + 'bind10.pid')
 
+class TestBrittle(unittest.TestCase):
+    def test_brittle_disabled(self):
+        bob = MockBob()
+        bob.start_all_processes()
+        bob.runnable = True
+
+        bob.reap_children()
+        self.assertTrue(bob.runnable)
+
+    def simulated_exit(self):
+        ret_val = self.exit_info
+        self.exit_info = (0, 0)
+        return ret_val
+
+    def test_brittle_enabled(self):
+        bob = MockBob()
+        bob.start_all_processes()
+        bob.runnable = True
+
+        bob.brittle = True
+        self.exit_info = (5, 0)
+        bob._get_process_exit_status = self.simulated_exit
+
+        bob.reap_children()
+        self.assertFalse(bob.runnable)
+
 if __name__ == '__main__':
     unittest.main()