initialise repo
[debian/mudpuppy.git] / modules / orchestra.py
1 from modules.base import Automatia
2 import config
3 import util
4
5 try: import json
6 except: import simplejson as json
7
8 class OrchestraAutomatia(Automatia):
9         """Abstract helper module to wrap an Orchestra score.
10
11         Use this helper to implement any item that can be directly 
12         mapped to a single Orchestra score.
13
14         Override do_magic() if you want to do more than just wrap a single 
15         score (almost multiple scores should almost certainly be instead made
16         multiple items in make-magic)
17
18         """
19         score_name = None
20         score_scope = 'one'
21         score_target = config.default_orchestra_target
22         score_args = {}
23         score_timeout = None
24
25         def do_magic(self):
26                 """Execute an Orchestra score."""
27                 if self.score_name == None:
28                         raise NotImplementedError(self.module_name + '.score_name')
29
30                 self.execute_score(
31                         self.score_name,
32                         self.score_scope,
33                         self.score_target,
34                         self.score_args,
35                         self.score_timeout)
36
37         @staticmethod
38         def execute_score(name, scope='one',
39                           target=config.default_orchestra_target, args={},
40                           timeout=None):
41                 """Execute an Orchestra score, block for completion, then return 
42                 the result as a (job_id, result) tuple.
43
44                 Will raise ``util.OrchestraError`` on any Orchestra failure.
45
46                 """
47                 oc = util.OrchestraClient()
48                 job_id = oc.submit_job(name, scope, target, args)
49                 result = oc.wait_for_completion(job_id, timeout=timeout)
50
51                 if result['Status'] == 'OK': 
52                         return (job_id, result, )
53                 else: 
54                         raise util.OrchestraError(repr(result))
55
56 class OrchestraMetadataAutomatia(OrchestraAutomatia):
57         '''Helper module to wrap an Orchestra score and update task metadata from the result
58         '''
59
60         # Mapping from orchestra response variables to metadata key names
61         orchestra_response_map = None
62
63         def get_variable_from_results(self, results, resultvarname):
64                 '''look through orchestra results and find the value keyed on resultvarname
65
66                 FIXME: THIS SHOULD BE IN util.py
67                 pre: results status is OK and players have completed the score
68                 '''
69                 # response looks like:
70                 # {u'Status': u'OK', u'Players': {u'orchestra.player.hostname.example': {u'Status': u'OK', u'Response': {u'echo': u'{"PATH": "/usr/bin:/usr/sbin:/bin:/sbin", "PWD": "/var/lib/service/player", "IFS": " \\t\\n", "ORC_foo": "bar", "ORC_fish": "heads"}'}}}} 
71                 assert results['Status'] == 'OK'
72                 for player,result in results['Players'].items():
73                         if result['Status'] != 'OK': continue
74                         for score,playerresponse in result['Response'].items():
75                                 playerresponse = json.loads(playerresponse) # UGH. This should NOT be in here  FIXME: Move unrolling to OrchestraClient
76                                 if playerresponse.has_key(resultvarname):
77                                         return playerresponse[resultvarname]
78                 return KeyError("Variable '"+resultvarname+"' not returned by any Orchestra player")
79
80         def do_magic(self):
81                 if self.orchestra_response_map == None: 
82                         raise NotImplementedError(str(self.module_name+'.orchestra_response_map'))
83                 results = self.execute_score(self.score_args)
84                 metadata_update = {}
85                 for response_var,metadata_key in self.orchestra_response_map.items():
86                         task_metadata_update[metadata_key] = self.get_variable_from_results(results, response_var)
87
88                 return dict(task_metadata_update=metadata_update)