diff options
author | Adrian Likins <alikins@redhat.com> | 2008-07-24 18:25:03 -0400 |
---|---|---|
committer | Adrian Likins <alikins@redhat.com> | 2008-07-24 18:25:03 -0400 |
commit | c5eae5219152d29e1d2d10f265afe701d8dbd2c2 (patch) | |
tree | d9b2817b8a9278fcc6f91a72bfad5caee5105f2d /func/overlord/client.py | |
parent | 8840c79028e59c6df17f20dd8c009f66324b6051 (diff) | |
parent | cf98349b19f8a44ca67d213ca79b7fc0abe519c9 (diff) | |
download | func-c5eae5219152d29e1d2d10f265afe701d8dbd2c2.tar.gz func-c5eae5219152d29e1d2d10f265afe701d8dbd2c2.tar.xz func-c5eae5219152d29e1d2d10f265afe701d8dbd2c2.zip |
Merge branch 'master' of ssh://alikins@git.fedoraproject.org/git/hosted/func
Diffstat (limited to 'func/overlord/client.py')
-rwxr-xr-x | func/overlord/client.py | 86 |
1 files changed, 76 insertions, 10 deletions
diff --git a/func/overlord/client.py b/func/overlord/client.py index a782b6e..dca53ce 100755 --- a/func/overlord/client.py +++ b/func/overlord/client.py @@ -16,6 +16,7 @@ import sys import glob import os +import time import func.yaml as yaml from certmaster.commonconfig import CMConfig @@ -172,6 +173,8 @@ class Overlord(object): self.minions_class = Minions(self.server_spec, port=self.port, noglobs=self.noglobs,verbose=self.verbose) self.minions = self.minions_class.get_urls() + if len(self.minions) == 0: + raise Func_Client_Exception, 'Can\'t find any minions matching \"%s\". ' % self.server_spec if self.delegate: try: @@ -244,6 +247,21 @@ class Overlord(object): # ----------------------------------------------- + def list_minions(self, format='list'): + """ + Returns a flat list containing the minions this Overlord object currently + controls + """ + if self.delegate: + return dtools.match_glob_in_tree(self.server_spec, self.minionmap) + minionlist = [] #nasty ugly hack to remove duplicate minions from list + for minion in self.minions_class.get_all_hosts(): + if minion not in minionlist: #ugh, brute force :( + minionlist.append(minion) + return minionlist + + # ----------------------------------------------- + def run(self, module, method, args, nforks=1): """ Invoke a remote method on one or more servers. @@ -258,25 +276,61 @@ class Overlord(object): if not self.delegate: #delegation is turned off, so run normally return self.run_direct(module, method, args, nforks) - resulthash = {} + delegatedhash = {} + directhash = {} + completedhash = {} #First we get all call paths for minions not directly beneath this overlord dele_paths = dtools.get_paths_for_glob(self.server_spec, self.minionmap) - non_single_paths = [path for path in dele_paths if len(path) > 1] - for path in non_single_paths: - resulthash.update(self.run_direct(module, + #Then we group them together in a dictionary by a common next hop + (single_paths,grouped_paths) = dtools.group_paths(dele_paths) + + for group in grouped_paths.keys(): + delegatedhash.update(self.run_direct(module, method, args, nforks, - call_path=path)) + call_path=grouped_paths[group], + suboverlord=group)) #Next, we run everything that can be run directly beneath this overlord #Why do we do this after delegation calls? Imagine what happens when #reboot is called... - resulthash.update(self.run_direct(module,method,args,nforks)) + directhash.update(self.run_direct(module,method,args,nforks)) - return resulthash + #poll async results if we've async turned on + if self.async: + while (len(delegatedhash) + len(directhash)) > 0: + for minion in delegatedhash.keys(): + results = delegatedhash[minion] + (return_code, async_results) = self.job_status(results) + if return_code == jobthing.JOB_ID_RUNNING: + pass + elif return_code == jobthing.JOB_ID_PARTIAL: + pass + else: + completedhash.update(async_results[minion]) + del delegatedhash[minion] + + for minion in directhash.keys(): + results = directhash[minion] + (return_code, async_results) = self.job_status(results) + if return_code == jobthing.JOB_ID_RUNNING: + pass + elif return_code == jobthing.JOB_ID_PARTIAL: + pass + else: + completedhash.update(async_results) + del directhash[minion] + time.sleep(0.1) #pause a bit so we don't flood our minions + return completedhash + + #we didn't instantiate this Overlord in async mode, so we just return the + #result hash + completedhash.update(delegatedhash) + completedhash.update(directhash) + return completedhash # ----------------------------------------------- @@ -327,12 +381,18 @@ class Overlord(object): # this is the point at which we make the remote call. if use_delegate: - retval = getattr(conn, meth)(module, method, args, delegation_path) + retval = getattr(conn, meth)(module, + method, + args, + delegation_path, + self.async, + self.nforks) else: retval = getattr(conn, meth)(*args[:]) if self.interactive: print retval + except Exception, e: (t, v, tb) = sys.exc_info() retval = utils.nice_exception(t,v,tb) @@ -349,10 +409,10 @@ class Overlord(object): return (server_name, retval) if kwargs.has_key('call_path'): #we're delegating if this key exists - spec = kwargs['call_path'][0] #the sub-overlord directly beneath this one + delegation_path = kwargs['call_path'] + spec = kwargs['suboverlord'] #the sub-overlord directly beneath this one minionobj = Minions(spec, port=self.port, verbose=self.verbose) use_delegate = True #signal to process_server to call delegate method - delegation_path = kwargs['call_path'][1:len(kwargs['call_path'])] minionurls = minionobj.get_urls() #the single-item url list to make async #tools such as jobthing/forkbomb happy else: #we're directly calling minions, so treat everything normally @@ -380,7 +440,13 @@ class Overlord(object): minions = expanded_minions.get_urls()[0] results = process_server(0, 0, minions) + if self.delegate and self.async: + return {spec:results} + if use_delegate: + if utils.is_error(results[spec]): + print results + return results return results[spec] return results |