summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSeth Vidal <skvidal@fedoraproject.org>2007-09-25 15:36:36 -0400
committerSeth Vidal <skvidal@fedoraproject.org>2007-09-25 15:36:36 -0400
commitb6b5546a32feaa8cd6d4f3edec10733d181526df (patch)
tree87caee8fe5a44744c4d76a2cf092569ef5851ce5
parent730ddae2ed9cfd102feda012d036f5ae6c5e4c8e (diff)
parent01cd1bdf7f1c7eb1de47cdbbe90b6c7f9b4f26eb (diff)
downloadthird_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-xoverlord/client.py223
-rwxr-xr-xoverlord/dumb_client.py50
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:])
-