#! /usr/bin/python # Eric LaForest, November 2008 # laforest AT eecg.utoronto.ca # Python Remote Objects import Pyro.core import Pyro.naming import Pyro.util import Pyro.errors import sys import os import pwd # FIXME # See server code for possible future improvements/fixes class batch_client: process_parameters = { 'cwd':None, 'uid':None, 'gid':None, 'logname':None, # FIXME add password request code 'passwd':None, 'env':None, } def __init__(self): self.get_process_parameters() def get_logname(self): """Gets username matching uid in /etc/passwd instead of the forgeable LOGNAME variable""" return pwd.getpwuid(os.getuid())[0] def get_process_parameters(self): self.process_parameters['cwd'] = os.getcwd() self.process_parameters['gid'] = os.getgid() self.process_parameters['uid'] = os.getuid() self.process_parameters['logname'] = self.get_logname() self.process_parameters['env'] = os.environ def usage(): instructions = """ Please supply your command as one quoted string, as if you were writing it by itself. e.g.: %s "my_command" The standard input, output, and error of your command are not accessible (meaning, you won't see anything, or read anything piped in) But you can redirect them to/from files, *inside the quotes*. e.g.: "my_command < infile > outfile" The return value is True (1) if your task was queued, False (0) otherwise. You can use this in a slow loop (use 'sleep'!) to automatically queue all your jobs in sequence. Give the command "show_queue" to see where everyone's job is sitting. The topmost entry is the currently running one. This command always returns True (1). """ % sys.argv[0] print instructions def print_exception_message(): message = """ *************************************************************** Congratulations! You've just raised an exception. Something is wrong with the batch client or server. Please immediately email the following text to the TA. *************************************************************** """ print message def print_exception_backtrace(exception): """Includes local and remote exception backtrace""" print ''.join(Pyro.util.getPyroTraceback(exception)) def batch_server(server_address, server_name): """See http://pyro.sourceforge.net/manual/4-usage.html""" try: Pyro.core.initClient(banner=0) locator = Pyro.naming.NameServerLocator() ns = locator.getNS(host = server_address) uri = ns.resolve(server_name) server = Pyro.core.getProxyForURI(uri) return server except Exception,x: print_exception_message() print "Summary: Likely either the Pyro Name Server or the batch server is not running.\n" print_exception_backtrace(x) sys.exit(False) def print_queue(queue): if len(queue) == 0: print "Queue Empty\n" return for (name, command) in queue: print "%s:\t%s" % (name, command) print def run_on_server(server, process_parameters, command): try: if command == "show_queue": print_queue(server.get_queue()) return True else: return server.queue_client_job(process_parameters, command) except Exception,x: print_exception_message() print "Summary: The server was unable to run your command. Badly so. It's dead, Jim.\n" print "process_parameters:%s\n" % process_parameters print "command:%s\n" % command print_exception_backtrace(x) sys.exit(False) def main(): if len(sys.argv) != 2: usage() return server = batch_server("localhost", "batch_server") client = batch_client() # only the first argument matters, other are discarded command = sys.argv[1] run_on_server(server, client.process_parameters, command) return True if __name__ == "__main__": # carry the return value to the shell sys.exit(main())