summaryrefslogtreecommitdiffstats
path: root/func/overlord/client.py
diff options
context:
space:
mode:
authorKrzysztof A. Adamski <krzysztofa@gmail.com>2008-07-24 22:43:18 +0200
committerKrzysztof A. Adamski <krzysztofa@gmail.com>2008-07-24 22:43:18 +0200
commitff5194eaf1145aab12de7b5b53191185983a5ea0 (patch)
tree3f3cf204b6ce644337c0e4c3265cb3b3558d98ed /func/overlord/client.py
parentcedd9198d92ed606fe47bb64cfbe8e0a4aa07ec8 (diff)
parent9944151ca91fa392d2944e92481ba9f08cee8607 (diff)
downloadfunc-ff5194eaf1145aab12de7b5b53191185983a5ea0.tar.gz
func-ff5194eaf1145aab12de7b5b53191185983a5ea0.tar.xz
func-ff5194eaf1145aab12de7b5b53191185983a5ea0.zip
Merge branch 'ssalevan-delegation'
Diffstat (limited to 'func/overlord/client.py')
-rwxr-xr-xfunc/overlord/client.py84
1 files changed, 74 insertions, 10 deletions
diff --git a/func/overlord/client.py b/func/overlord/client.py
index 79ead06..b322f76 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
@@ -244,6 +245,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 +274,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 +379,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 +407,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 +438,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