diff options
author | Seth Vidal <skvidal@fedoraproject.org> | 2007-09-25 15:36:36 -0400 |
---|---|---|
committer | Seth Vidal <skvidal@fedoraproject.org> | 2007-09-25 15:36:36 -0400 |
commit | b6b5546a32feaa8cd6d4f3edec10733d181526df (patch) | |
tree | 87caee8fe5a44744c4d76a2cf092569ef5851ce5 | |
parent | 730ddae2ed9cfd102feda012d036f5ae6c5e4c8e (diff) | |
parent | 01cd1bdf7f1c7eb1de47cdbbe90b6c7f9b4f26eb (diff) | |
download | third_party-func-b6b5546a32feaa8cd6d4f3edec10733d181526df.tar.gz third_party-func-b6b5546a32feaa8cd6d4f3edec10733d181526df.tar.xz third_party-func-b6b5546a32feaa8cd6d4f3edec10733d181526df.zip |
Merge branch 'master' of ssh://git.fedoraproject.org/git/hosted/func
* 'master' of ssh://git.fedoraproject.org/git/hosted/func:
Adding client module, which contains code for both the CLI and those
-rwxr-xr-x | overlord/client.py | 223 | ||||
-rwxr-xr-x | overlord/dumb_client.py | 50 |
2 files changed, 223 insertions, 50 deletions
diff --git a/overlord/client.py b/overlord/client.py new file mode 100755 index 0000000..303a4df --- /dev/null +++ b/overlord/client.py @@ -0,0 +1,223 @@ +#!/usr/bin/python + +## +## func command line interface & client lib +## +## Copyright 2007, Red Hat, Inc +## Michael DeHaan <mdehaan@redhat.com> +## +AUTHORS +## +## This software may be freely redistributed under the terms of the GNU +## general public license. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## + +import optparse +import sys +import xmlrpclib +import traceback + +# =================================== +# defaults +# TO DO: some of this may want to come from config later + +DEFAULT_PORT = 51234 +FUNC_USAGE = "Usage: %s [ --help ] [ --verbose ] target.example.org module method arg1 [...]" + +# =================================== + +class Client(): + + def __init__(self, server_spec, port=DEFAULT_PORT, verbose=False, silent=False): + """ + Constructor. + server_spec is something like "*.example.org" or "foosball" + everything else optional and mostly self explanatory. + """ + + self.server_spec = server_spec + self.port = port + self.verbose = verbose + self.silent = silent + self.servers = self.expand_servers(self.server_spec) + + # ----------------------------------------------- + + def expand_servers(self,spec): + """ + Given a regex/blob of servers, expand to a list + of server ids. + """ + + # FIXME: currently globbing is not supported (yet) + # needs knowledge of the tree of certs + # will be done soon + + results = [] + + # FIXME: add SSL + results.append("http://%s:%s" % (spec, self.port)) + return results + + # ----------------------------------------------- + + def run(self, module, method, args): + """ + Invoke a remote method on one or more servers. + """ + + count = len(self.servers) + results = [] + + for server in self.servers: + + # FIXME: add SSL + + conn = xmlrpclib.ServerProxy(server) + + if self.verbose: + sys.stderr.write("on %s running %s %s (%s)\n" % (server, module, method, ",".join(args))) + + # FIXME: support userland command subclassing only if a module + # is present, otherwise run as follows. -- MPD + + try: + # thats some pretty code right there aint it? -akl + # we can't call "call" on s, since thats a rpc, so + # we call gettatr around it. + meth = "%s.%s" % (module, method) + retval = getattr(conn, meth)(*args[:]) + if not self.silent: + print retval + except Exception, e: + retval = e + if not self.silent: + sys.stderr.write("remote exception on %s: %s\n" % (server, str(e))) + + results.append(retval) + + return results + + # ----------------------------------------------- + + def cli_return(self,results): + """ + As the return code list could return strings and exceptions + and all sorts of crazy stuff, reduce it down to a simple + integer return. It may not be useful but we need one. + """ + nonzeros = [] + for x in results: + # faults are the most important + if type(x) == Exception: + return -911 + # then pay attention to non-zeros + if type(x) == int: + nonzeros.append(x) + if len(nonzeros) > 0: + return nonzeros[1] + return 0 + +# =================================================================== + +class FuncCommandLine(): + + def __init__(self,myname,args): + """ + Constructor. Takes name of program + arguments. + """ + self.myname = myname + self.args = args + self.verbose = 0 + self.server_spec = None + self.port = DEFAULT_PORT + + # ----------------------------------------------- + + def usage(self): + """ + Returns usage string for command line users. + """ + return FUNC_USAGE % self.myname + + # ----------------------------------------------- + + def run(self): + """ + Engages the command line. + """ + + rc = self.parse_command_line() + if rc != 0: + return rc + + return self.run_command() + + # ----------------------------------------------- + + def parse_command_line(self): + """ + Parses the command line and loads up all the variables. + """ + + # parse options + p = optparse.OptionParser() + p.add_option("-v","--verbose",dest="verbose",action="store_true") + p.add_option("-p","--port",dest="port",default=DEFAULT_PORT) + (options, args) = p.parse_args(self.args) + + self.args = args + self.verbose = options.verbose + self.port = options.port + # self.help = options.help + + # provided for free: + # + #if self.help: + # print self.usage() + # return -411 + + # process arguments + # a good Klingon program does not have parameters + # it has arguments, and it always wins them. + + if len(args) < 3: + print self.usage() + return -411 + + self.server_spec = self.args[0] + self.module = self.args[1] + self.method = self.args[2] + self.method_args = self.args[3:] + + return 0 + + # ----------------------------------------------- + + def run_command(self): + """ + Runs the actual command. + """ + client = Client(self.server_spec,port=self.port,verbose=self.verbose) + results = client.run(self.module, self.method, self.method_args) + + # TO DO: add multiplexer support + # probably as a higher level module. + + return client.cli_return(results) + + +# =================================================================== + + +if __name__ == "__main__": + # this is what /usr/bin/func will run + myname, argv = sys.argv[0], sys.argv[1:] + cli = FuncCommandLine(myname,argv) + rc = cli.run() + sys.exit(rc) + + diff --git a/overlord/dumb_client.py b/overlord/dumb_client.py deleted file mode 100755 index c6a31ed..0000000 --- a/overlord/dumb_client.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/python - - -# all the cool kids would use optparse instead -import getopt -import sys -import xmlrpclib - -myname, argv = sys.argv[0], sys.argv[1:] - -def usage(): - return "Usage: %s [ --help ] [ --verbose ] [ --server=http://hostname:port ] method arg1 [ ... ]" % myname - -verbose = 0 -server = "http://127.0.0.1:51234" - -try: - opts, args = getopt.getopt(argv, "hvs:", - ["help", - "verbose", - "server="]) -except getopt.error, e: - print _("Error parsing list arguments: %s") % e - print usage() - sys.exit() - -for (opt, val) in opts: - print "opt = %s, val = %s" % (opt, val) - if opt in ["-h", "--help"]: - print usage() - sys.exit() - if opt in ["-v", "--verbose"]: - verbose = verbose + 1 - if opt in ["-s", "--server"]: - server = val - -if len(args) < 1: - print usage() - sys.exit() - -s = xmlrpclib.ServerProxy(server) - -method = args[0] -print "calling %s with args: %s" % (method, args[1:]) - -# thats some pretty code right there aint it? -akl -# we can't call "call" on s, since thats a rpc, so -# we call gettatr around it. -print getattr(s, method)(*args[1:]) - |