Commit 3ceeab28 authored by Shane Kerr's avatar Shane Kerr

Implement "--brittle" option.

parent 888bcbc1
......@@ -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)
......
......@@ -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()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment