From bfc293cf605ecca02f8d45e27c33909c7778e649 Mon Sep 17 00:00:00 2001 From: Michael DeHaan Date: Wed, 26 Sep 2007 13:32:01 -0400 Subject: Two things. First Client("*").hardware.info() and the like now works, due to some clever magic with getattr. You have one client object that can address multiples and returns a hash with the results for each machine. Second, results are hashes, not lists, and we are a bit more clever in returning a return code the CLI .. the highest int wins if there's an int, for instance. Still, return codes are relatively meaningless for multi-control ... the true power is in scripting things. --- overlord/client.py | 69 ++++++++++++++++++++++++++++++++++++++++++++------- overlord/test_func.py | 7 ++++++ 2 files changed, 67 insertions(+), 9 deletions(-) (limited to 'overlord') diff --git a/overlord/client.py b/overlord/client.py index 3427e20..87b665a 100755 --- a/overlord/client.py +++ b/overlord/client.py @@ -33,6 +33,32 @@ FUNC_USAGE = "Usage: %s [ --help ] [ --verbose ] target.example.org module metho # =================================== +class CommandAutomagic(): + """ + This allows a client object to act as if it were one machine, when in + reality it represents many. + """ + + def __init__(self, clientref, base): + self.base = base + self.clientref = clientref + + def __getattr__(self,name): + base2 = self.base[:] + base2.append(name) + return CommandAutomagic(self.clientref, base2) + + def __call__(self, *args): + if not self.base: + raise AttributeError("something wrong here") + if len(self.base) < 2: + raise AttributeError("no method called: %s" % ".".join(self.base)) + module = self.base[0] + method = ".".join(self.base[1:]) + return self.clientref.run(module,method,args) + +# =================================== + class Client(): def __init__(self, server_spec, port=DEFAULT_PORT, verbose=False, silent=False): @@ -79,6 +105,22 @@ class Client(): return all_urls + # ----------------------------------------------- + + def __getattr__(self, name): + """ + This getattr allows manipulation of the object as if it were + a XMLRPC handle to a single machine, when in reality it is a handle + to an unspecified number of machines. + + So, it enables stuff like this: + + Client("*.example.org").yum.install("foo") + """ + + return CommandAutomagic(self, [name]) + + # ----------------------------------------------- def run(self, module, method, args): @@ -87,7 +129,7 @@ class Client(): """ count = len(self.servers) - results = [] + results = {} for server in self.servers: @@ -114,7 +156,7 @@ class Client(): if not self.silent: sys.stderr.write("remote exception on %s: %s\n" % (server, str(e))) - results.append(retval) + results[server] = retval return results @@ -126,17 +168,26 @@ class Client(): 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: + numbers = [] + for x in results.keys(): # faults are the most important if type(x) == Exception: return -911 - # then pay attention to non-zeros + # then pay attention to numbers if type(x) == int: - nonzeros.append(x) - if len(nonzeros) > 0: - return nonzeros[1] - return 0 + numbers.append(x) + + # if there were no numbers, assume 0 + if len(numbers) == 0: + return 0 + + # if there were numbers, return the highest + # (presumably the worst error code + max = -9999 + for x in numbers: + if x > max: + max = x + return max # =================================================================== diff --git a/overlord/test_func.py b/overlord/test_func.py index bcce45d..d759a2e 100644 --- a/overlord/test_func.py +++ b/overlord/test_func.py @@ -4,13 +4,20 @@ # FIXME: should import the client lib, not XMLRPC lib, when we are done import xmlrpclib +import sys +TEST_GETATTR = True TEST_PROCESS = False TEST_VIRT = False TEST_SERVICES = False TEST_HARDWARE = False TEST_SMART = True +if TEST_GETATTR: + import func.overlord.client as func_client + print func_client.Client("*").hardware.info() + sys.exit(1) + # get a connecton (to be replaced by client lib logic) s = xmlrpclib.ServerProxy("http://127.0.0.1:51234") -- cgit