[svn] commit: r520 - in /branches/parkinglot/src/bin/bind10: TODO bind10.py bind10_test.py
BIND 10 source code commits
bind10-changes at lists.isc.org
Tue Jan 26 20:03:47 UTC 2010
Author: shane
Date: Tue Jan 26 20:03:47 2010
New Revision: 520
Log:
First BoB tests created
Respect verbose flag when starting BoB
Make message processing robust
Refactor to make testable
Convert from poll() to select()
Update TODO list
Modified:
branches/parkinglot/src/bin/bind10/TODO
branches/parkinglot/src/bin/bind10/bind10.py
branches/parkinglot/src/bin/bind10/bind10_test.py
Modified: branches/parkinglot/src/bin/bind10/TODO
==============================================================================
--- branches/parkinglot/src/bin/bind10/TODO (original)
+++ branches/parkinglot/src/bin/bind10/TODO Tue Jan 26 20:03:47 2010
@@ -11,5 +11,7 @@
- Back-off mechanism for restarting failed processes
- Start statistics daemon
- Statistics interaction (?)
-- Stop using poll(), as primitive operating systems (OS X) don't support it
- Use .spec file to define comands
+- Rename "c-channel" stuff to msgq for clarity
+- Use logger
+- Reply to shutdown message?
Modified: branches/parkinglot/src/bin/bind10/bind10.py
==============================================================================
--- branches/parkinglot/src/bin/bind10/bind10.py (original)
+++ branches/parkinglot/src/bin/bind10/bind10.py Tue Jan 26 20:03:47 2010
@@ -81,7 +81,7 @@
process listens on. If verbose is True, then the boss reports
what it is doing.
"""
- self.verbose = True
+ self.verbose = verbose
self.c_channel_port = c_channel_port
self.cc_session = None
self.processes = {}
@@ -153,7 +153,7 @@
if self.verbose:
sys.stdout.write("Starting cmd-ctrld on port 8080\n")
try:
- cmd_ctrld = ProcessInfo("cmd-ctrld", 'cmd-ctrld')
+ cmd_ctrld = ProcessInfo("cmd-ctrld", ['cmd-ctrld'])
except Exception as e:
c_channel.process.kill()
bind_cfgd.process.kill()
@@ -247,32 +247,59 @@
def recv_and_process_cc_msg(self):
"""Receive and process the next message on the c-channel,
if any."""
- # XXX: this needs to be made more robust for handling
- # badly formatted messages
- msg, data = self.cc_session.group_recvmsg(False)
+ msg, envelope = self.cc_session.group_recvmsg(False)
+ print(msg)
if msg is None:
return
- msg_from = data.get('from', '')
-
- if (type(msg) is dict) and (type(data) is dict):
- if "command" in msg:
- cmd = msg['command']
- if cmd[0] == "shutdown":
- if self.verbose:
- sys.stdout.write("Shutdown command received\n")
- self.runnable = False
- else:
- if self.verbose:
- sys.stdout.write("Unknown command %s\n" % str(cmd))
- else:
- if self.verbose:
- del data['msg']
- sys.stdout.write("Unknown message received\n")
- sys.stdout.write(pprint.pformat(data) + "\n")
- sys.stdout.write(pprint.pformat(msg) + "\n")
+ if not ((type(msg) is dict) and (type(envelope) is dict)):
+ if self.verbose:
+ sys.stdout.write("Non-dictionary message\n")
+ return
+ if not "command" in msg:
+ if self.verbose:
+ if "msg" in envelope:
+ del envelope['msg']
+ sys.stdout.write("Unknown message received\n")
+ sys.stdout.write(pprint.pformat(envelope) + "\n")
+ sys.stdout.write(pprint.pformat(msg) + "\n")
+ return
+ cmd = msg['command']
+ if not (type(cmd) is list):
+ if self.verbose:
+ sys.stdout.write("Non-list command\n")
+ return
+ if len(cmd) < 2:
+ if self.verbose:
+ sys.stdout.write("Command too short\n")
+ return
+ if cmd[0] != "boss":
+ return
+
+ # done checking and extracting... time to execute the command
+ if cmd[1] == "shutdown":
+ if self.verbose:
+ sys.stdout.write("shutdown command received\n")
+ self.runnable = False
+ # XXX: reply here?
+ elif cmd[1] == "getProcessList":
+ if self.verbose:
+ sys.stdout.write("getProcessList command received\n")
+ live_processes = [ ]
+ for proc_info in processes:
+ live_processes.append({ "name": proc_info.name,
+ "args": proc_info.args,
+ "pid": proc_info.pid, })
+ dead_processes = [ ]
+ for proc_info in dead_processes:
+ dead_processes.append({ "name": proc_info.name,
+ "args": proc_info.args, })
+ cc.group_reply(envelope, { "response": cmd,
+ "sent": msg["sent"],
+ "live_processes": live_processes,
+ "dead_processes": dead_processes, })
else:
if self.verbose:
- sys.stdout.write("Non-dictionary message\n")
+ sys.stdout.write("Unknown command %s\n" % str(cmd))
def restart_processes(self):
"""Restart any dead processes."""
@@ -297,38 +324,41 @@
# remember any processes that refuse to be resurrected
self.dead_processes = still_dead
-if __name__ == "__main__":
- def reaper(signal_number, stack_frame):
- """A child process has died (SIGCHLD received)."""
- # don't do anything...
- # the Python signal handler has been set up to write
- # down a pipe, waking up our select() bit
- pass
+def reaper(signal_number, stack_frame):
+ """A child process has died (SIGCHLD received)."""
+ # don't do anything...
+ # the Python signal handler has been set up to write
+ # down a pipe, waking up our select() bit
+ pass
- def get_signame(signal_number):
- """Return the symbolic name for a signal."""
- for sig in dir(signal):
- if sig.startswith("SIG") and sig[3].isalnum():
- if getattr(signal, sig) == signal_number:
- return sig
- return "Unknown signal %d" % signal_number
-
- # XXX: perhaps register atexit() function and invoke that instead
- def fatal_signal(signal_number, stack_frame):
- """We need to exit (SIGINT or SIGTERM received)."""
- global options
- if options.verbose:
- sys.stdout.write("Received %s.\n" % get_signame(signal_number))
- signal.signal(signal.SIGCHLD, signal.SIG_DFL)
- boss_of_bind.runnable = False
-
- def check_port(option, opt_str, value, parser):
- """Function to insure that the port we are passed is actually
- a valid port number. Used by OptionParser() on startup."""
- if not re.match('^(6553[0-5]|655[0-2]\d|65[0-4]\d\d|6[0-4]\d{3}|[1-5]\d{4}|[1-9]\d{0,3}|0)$', value):
- raise OptionValueError("%s requires a port number (0-65535)" % opt_str)
- parser.values.msgq_port = value
-
+def get_signame(signal_number):
+ """Return the symbolic name for a signal."""
+ for sig in dir(signal):
+ if sig.startswith("SIG") and sig[3].isalnum():
+ if getattr(signal, sig) == signal_number:
+ return sig
+ return "Unknown signal %d" % signal_number
+
+# XXX: perhaps register atexit() function and invoke that instead
+def fatal_signal(signal_number, stack_frame):
+ """We need to exit (SIGINT or SIGTERM received)."""
+ global options
+ global boss_of_bind
+ if options.verbose:
+ sys.stdout.write("Received %s.\n" % get_signame(signal_number))
+ signal.signal(signal.SIGCHLD, signal.SIG_DFL)
+ boss_of_bind.runnable = False
+
+def check_port(option, opt_str, value, parser):
+ """Function to insure that the port we are passed is actually
+ a valid port number. Used by OptionParser() on startup."""
+ if not re.match('^(6553[0-5]|655[0-2]\d|65[0-4]\d\d|6[0-4]\d{3}|[1-5]\d{4}|[1-9]\d{0,3}|0)$', value):
+ raise OptionValueError("%s requires a port number (0-65535)" % opt_str)
+ parser.values.msgq_port = value
+
+def main():
+ global options
+ global boss_of_bind
# Parse any command-line options.
parser = OptionParser(version=__version__)
parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
@@ -366,27 +396,24 @@
# In our main loop, we check for dead processes or messages
# on the c-channel.
- event_poller = select.poll()
wakeup_fd = wakeup_pipe[0]
- event_poller.register(wakeup_fd, select.POLLIN)
cc_fd = boss_of_bind.cc_session._socket.fileno()
- event_poller.register(cc_fd, select.POLLIN)
while boss_of_bind.runnable:
- # XXX: get time for next restart for poll
-
- # poll() can raise EINTR when a signal arrives,
+ # XXX: get time for next restart for timeout
+
+ # select() can raise EINTR when a signal arrives,
# even if they are resumable, so we have to catch
# the exception
try:
- events = event_poller.poll()
+ (rlist, wlist, xlist) = select.select([wakeup_fd, cc_fd], [], [])
except select.error as err:
if err.args[0] == errno.EINTR:
- events = []
+ (rlist, wlist, xlist) = ([], [], [])
else:
- sys.stderr.write("Error with poll(); %s\n" % err)
+ sys.stderr.write("Error with select(); %s\n" % err)
break
- for (fd, event) in events:
+ for fd in rlist + xlist:
if fd == cc_fd:
boss_of_bind.recv_and_process_cc_msg()
elif fd == wakeup_fd:
@@ -402,9 +429,12 @@
raise
if pid == 0: break
boss_of_bind.reap(pid, exit_status)
-
+
boss_of_bind.restart_processes()
# shutdown
signal.signal(signal.SIGCHLD, signal.SIG_DFL)
boss_of_bind.shutdown()
+
+if __name__ == "__main__":
+ main()
Modified: branches/parkinglot/src/bin/bind10/bind10_test.py
==============================================================================
--- branches/parkinglot/src/bin/bind10/bind10_test.py (original)
+++ branches/parkinglot/src/bin/bind10/bind10_test.py Tue Jan 26 20:03:47 2010
@@ -1,4 +1,4 @@
-from bind10 import ProcessInfo
+from bind10 import ProcessInfo, BoB
import unittest
import sys
@@ -68,5 +68,26 @@
self.assertTrue(type(pi.pid) is int)
self.assertNotEqual(pi.pid, old_pid)
+class TestBoB(unittest.TestCase):
+ def test_init(self):
+ bob = BoB()
+ self.assertEqual(bob.verbose, False)
+ self.assertEqual(bob.c_channel_port, 9912)
+ self.assertEqual(bob.cc_session, None)
+ self.assertEqual(bob.processes, {})
+ self.assertEqual(bob.dead_processes, {})
+ self.assertEqual(bob.runnable, False)
+
+ def test_init_alternate_port(self):
+ bob = BoB(2199)
+ self.assertEqual(bob.verbose, False)
+ self.assertEqual(bob.c_channel_port, 2199)
+ self.assertEqual(bob.cc_session, None)
+ self.assertEqual(bob.processes, {})
+ self.assertEqual(bob.dead_processes, {})
+ self.assertEqual(bob.runnable, False)
+
+ # verbose testing...
+
if __name__ == '__main__':
unittest.main()
More information about the bind10-changes
mailing list