ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/COMP/CRAB/python/crab.py
Revision: 1.3
Committed: Wed Jun 22 15:14:57 2005 UTC (19 years, 10 months ago) by nsmirnov
Content type: text/x-python
Branch: MAIN
Changes since 1.2: +83 -101 lines
Log Message:
The '-continue' option implemented

File Contents

# User Rev Content
1 nsmirnov 1.1 #!/usr/bin/env python
2     from crab_help import *
3     from crab_util import *
4     from crab_exceptions import *
5     from crab_logger import Logger
6     from WorkSpace import WorkSpace
7     from JobDB import JobDB
8 nsmirnov 1.3 from JobList import JobList
9 nsmirnov 1.1 from Creator import Creator
10     from Submitter import Submitter
11     import common
12    
13     import sys, os, time, string
14    
15     ###########################################################################
16     class Crab:
17 nsmirnov 1.3 def __init__(self, opts):
18 nsmirnov 1.1
19     # The order of main_actions is important !
20     self.main_actions = [ '-create', '-submit', '-resubmit',
21     '-monitor', '-retrieve' ]
22     self.aux_actions = [ '-kill', '-status' ]
23    
24     # Dictionary of actions, e.g. '-create' -> object of class Creator
25     self.actions = {}
26    
27     # Configuration file
28     self.cfg_fname = None
29     # Dictionary with configuration parameters
30     self.cfg_params = {}
31    
32     # Current working directory
33     self.cwd = os.getcwd()+'/'
34     # Current time in format 'yymmdd_hhmmss'
35     self.current_time = time.strftime('%y%m%d_%H%M%S',
36     time.localtime(time.time()))
37    
38 nsmirnov 1.3 # Session name (?) Do we need this ?
39 nsmirnov 1.1 self.name = '0'
40    
41     # Job type
42     self.job_type_name = None
43    
44     # Continuation flag
45     self.flag_continue = 0
46    
47     # quiet mode, i.e. no output on screen
48     self.flag_quiet = 0
49     # produce more output
50     self.debug_level = 0
51    
52 nsmirnov 1.3 # Scheduler name, e.g. 'edg', 'lsf'
53 nsmirnov 1.1 self.scheduler_name = 'edg'
54    
55 nsmirnov 1.3 self.initialize_(opts)
56 nsmirnov 1.1
57     return
58    
59     def version(self):
60     return common.prog_version_str
61    
62 nsmirnov 1.3 def initialize_(self, opts):
63 nsmirnov 1.1
64     # Process the '-continue' option first because
65     # in the case of continuation the CRAB configuration
66     # parameters are loaded from already existing Working Space.
67 nsmirnov 1.3 self.processContinueOption_(opts)
68 nsmirnov 1.1
69     # Process ini-file first, then command line options
70     # because they override ini-file settings.
71    
72 nsmirnov 1.3 self.processIniFile_(opts)
73 nsmirnov 1.1
74 nsmirnov 1.3 if self.flag_continue: opts = self.loadConfiguration_(opts)
75 nsmirnov 1.1
76 nsmirnov 1.3 self.processOptions_(opts)
77 nsmirnov 1.1
78     if not self.flag_continue:
79 nsmirnov 1.3 self.createWorkingSpace_()
80 nsmirnov 1.1 common.work_space.saveConfiguration(opts, self.cfg_fname)
81     pass
82    
83     # At this point all configuration options have been read.
84    
85     args = string.join(sys.argv,' ')
86 nsmirnov 1.3 self.updateHistory_(args)
87     self.createLogger_(args)
88 nsmirnov 1.1 common.jobDB = JobDB()
89 nsmirnov 1.3 if self.flag_continue:
90     common.jobDB.load()
91     common.logger.debug(6, str(common.jobDB))
92     pass
93     self.createScheduler_()
94     if common.logger.debugLevel() >= 6:
95     common.logger.debug(6, 'Used properties:')
96     keys = self.cfg_params.keys()
97     keys.sort()
98     for k in keys:
99     if self.cfg_params[k]:
100     common.logger.debug(6, ' '+k+' : '+self.cfg_params[k])
101     pass
102     else:
103     common.logger.debug(6, ' '+k+' : ')
104     pass
105     pass
106     common.logger.debug(6, 'End of used properties.\n')
107     pass
108     self.initializeActions_(opts)
109 nsmirnov 1.1 return
110    
111 nsmirnov 1.3 def processContinueOption_(self,opts):
112 nsmirnov 1.1
113     continue_dir = None
114    
115     for opt in opts.keys():
116     if ( opt in ('-continue','-c') ):
117     self.flag_continue = 1
118     val = opts[opt]
119     if val:
120     if val[0] == '/': continue_dir = val # abs path
121     else: continue_dir = self.cwd + val # rel path
122     pass
123     pass
124     pass
125    
126     if not self.flag_continue: return
127    
128    
129     if not continue_dir:
130     prefix = common.prog_name + '_' + self.name + '_'
131     continue_dir = findLastWorkDir(prefix)
132     pass
133    
134     if not continue_dir:
135     raise CrabException('Cannot find last working directory.')
136    
137     if not os.path.exists(continue_dir):
138     msg = 'Cannot continue because the working directory <'
139     msg += continue_dir
140     msg += '> does not exist.'
141     raise CrabException(msg)
142    
143     # Instantiate WorkSpace
144     common.work_space = WorkSpace(continue_dir)
145    
146     return
147    
148 nsmirnov 1.3 def processIniFile_(self, opts):
149 nsmirnov 1.1 """
150     Processes a configuration INI-file.
151     """
152    
153     # Extract cfg-file name from the cmd-line options.
154    
155     for opt in opts.keys():
156     if ( opt == '-cfg' ):
157     if self.flag_continue:
158     raise CrabException('-continue and -cfg cannot coexist.')
159     if opts[opt] : self.cfg_fname = opts[opt]
160     else : usage()
161     pass
162    
163     elif ( opt == '-name' ):
164     self.name = opts[opt]
165     pass
166    
167     pass
168    
169     # Set default cfg-fname
170    
171     if self.cfg_fname == None:
172     if self.flag_continue:
173     self.cfg_fname = common.work_space.cfgFileName()
174     else:
175     self.cfg_fname = common.prog_name+'.cfg'
176     pass
177     pass
178    
179     # Load cfg-file
180    
181     if string.lower(self.cfg_fname) != 'none':
182     if os.path.exists(self.cfg_fname):
183     self.cfg_params = loadConfig(self.cfg_fname)
184     pass
185     else:
186     msg = 'cfg-file '+self.cfg_fname+' not found.'
187     raise CrabException(msg)
188     pass
189     pass
190    
191     # process the [CRAB] section
192    
193     lhp = len('CRAB.')
194     for k in self.cfg_params.keys():
195     if len(k) >= lhp and k[:lhp] == 'CRAB.':
196     opt = '-'+k[lhp:]
197     if len(opt) >= 3 and opt[:3] == '-__': continue
198     if opt not in opts.keys():
199     opts[opt] = self.cfg_params[k]
200     pass
201     pass
202     pass
203    
204     return
205    
206 nsmirnov 1.3 def processOptions_(self, opts):
207 nsmirnov 1.1 """
208     Processes the command-line options.
209     """
210    
211     for opt in opts.keys():
212     val = opts[opt]
213    
214 nsmirnov 1.3 # Skip actions, they are processed later in initializeActions_()
215     if opt in self.main_actions:
216     self.cfg_params['CRAB.'+opt[1:]] = val
217     continue
218     if opt in self.aux_actions:
219     self.cfg_params['CRAB.'+opt[1:]] = val
220     continue
221 nsmirnov 1.1
222    
223     elif ( opt == '-cfg' ):
224     pass
225    
226     elif ( opt in ('-continue', '-c') ):
227     pass
228    
229     elif ( opt == '-jobtype' ):
230     if val : self.job_type_name = string.upper(val)
231     else : usage()
232     pass
233    
234     elif ( opt == '-Q' ):
235     self.flag_quiet = 1
236     pass
237    
238     elif ( opt == '-debug' ):
239 nsmirnov 1.2 self.debug_level = int(val)
240 nsmirnov 1.1 pass
241    
242     elif ( opt == '-scheduler' ):
243     if val: self.scheduler_name = val
244     else:
245     print common.prog_name+". No value for '-scheduler'."
246     usage()
247     pass
248     pass
249    
250 nsmirnov 1.3 elif string.find(opt,'.') == -1:
251     print common.prog_name+'. Unrecognized option '+opt
252     usage()
253     pass
254 nsmirnov 1.1
255 nsmirnov 1.3 # Override config parameters from INI-file with cmd-line params
256     if string.find(opt,'.') == -1 :
257     self.cfg_params['CRAB.'+opt[1:]] = val
258 nsmirnov 1.1 pass
259 nsmirnov 1.3 else:
260 nsmirnov 1.1 # Command line parameters in the form -SECTION.ENTRY=VALUE
261     self.cfg_params[opt[1:]] = val
262     pass
263     pass
264     return
265    
266 nsmirnov 1.3 def initializeActions_(self, opts):
267 nsmirnov 1.1 """
268     For each user action instantiate a corresponding
269     object and put it in the action dictionary.
270     """
271    
272     for opt in opts.keys():
273     val = opts[opt]
274    
275     if ( opt == '-create' ):
276     if val:
277     if ( isInt(val) ):
278     ncjobs = int(val)
279     elif ( val == 'all'):
280     ncjobs = val
281     else:
282     print common.prog_name+'. Bad creation bunch size',val
283     print ' Must be an integer or "all"'
284     pass
285     pass
286     else: ncjobs = 'all'
287    
288     if ncjobs != 0:
289 nsmirnov 1.3 # Instantiate Creator object
290 nsmirnov 1.1 creator = Creator(self.job_type_name,
291     self.cfg_params,
292     ncjobs)
293     self.actions[opt] = creator
294 nsmirnov 1.3
295     # Initialize the JobDB object if needed
296 nsmirnov 1.1 if not self.flag_continue:
297     common.jobDB.create(creator.nJobs())
298     pass
299 nsmirnov 1.3
300     # Create and initialize JobList
301    
302     common.job_list = JobList(common.jobDB.nJobs(),
303     creator.jobType())
304    
305     common.job_list.setScriptNames(self.job_type_name+'.sh')
306     common.job_list.setJDLNames(self.job_type_name+'.jdl')
307     creator.jobType().setSteeringCardsNames()
308 nsmirnov 1.1 pass
309 nsmirnov 1.3 pass
310 nsmirnov 1.1
311     elif ( opt == '-submit' ):
312     if val:
313     if ( isInt(val) ):
314     nsjobs = int(val)
315     elif ( val == 'all'):
316     nsjobs = val
317     else:
318     print common.prog_name+'. Bad submission bunch size',val
319     print ' Must be an integer or "all"'
320     pass
321     pass
322     else: nsjobs = 'all'
323    
324     if nsjobs != 0:
325 nsmirnov 1.3 # Instantiate Submitter object
326 nsmirnov 1.1 self.actions[opt] = Submitter(self.cfg_params, nsjobs)
327 nsmirnov 1.3
328     # Create and initialize JobList
329    
330     if len(common.job_list) == 0 :
331     common.job_list = JobList(common.jobDB.nJobs(),
332     None)
333     common.job_list.setJDLNames(self.job_type_name+'.jdl')
334     pass
335 nsmirnov 1.1 pass
336 nsmirnov 1.3 pass
337 nsmirnov 1.1
338     elif ( opt == '-resubmit' ):
339     # TODO
340     common.flag_resubmit = 1
341     if val:
342     (common.resubmit_from,common.resubmit_to) =parseJobidRange(val)
343     if ( common.resubmit_to == None or
344     common.resubmit_from > common.resubmit_to ):
345     print common.prog_name+'. Bad BOSS JobId range ['+val+']'
346     usage()
347     pass
348     pass
349     else: usage()
350    
351     elif ( opt == '-status' ):
352     # TODO
353     pass
354    
355     elif ( opt == '-monitor' ):
356     # TODO
357     if val and ( isInt(val) ):
358     common.delay = val
359     else:
360     common.delay = 60
361     pass
362     common.autoretrieve = 1
363     pass
364    
365     elif ( opt == '-retrieve' ):
366     # TODO
367     if val and ( isInt(val) ):
368     common.delay = val
369     else:
370     common.delay = 60
371     pass
372     common.autoretrieve = 1
373     pass
374    
375    
376     elif ( opt == '-kill' ):
377     # TODO
378     jobMon = retrieve.Monitor()
379     jobMon.killJobs()
380     sys.exit()
381    
382     pass
383     return
384    
385 nsmirnov 1.3 def createWorkingSpace_(self):
386 nsmirnov 1.1 new_dir = common.prog_name + '_' + self.name + '_' + self.current_time
387     new_dir = self.cwd + new_dir
388     common.work_space = WorkSpace(new_dir)
389     common.work_space.create()
390     return
391    
392 nsmirnov 1.3 def loadConfiguration_(self, opts):
393 nsmirnov 1.1
394     save_opts = common.work_space.loadSavedOptions()
395    
396     # Override saved options with new command-line options
397    
398     for k in opts.keys():
399     save_opts[k] = opts[k]
400     pass
401    
402     # Return updated options
403     return save_opts
404    
405 nsmirnov 1.3 def createLogger_(self, args):
406 nsmirnov 1.1
407     log = Logger()
408     log.quiet(self.flag_quiet)
409     log.setDebugLevel(self.debug_level)
410     log.write(args+'\n')
411 nsmirnov 1.3 log.message(self.headerString_())
412 nsmirnov 1.1 log.flush()
413     common.logger = log
414     return
415    
416 nsmirnov 1.3 def updateHistory_(self, args):
417 nsmirnov 1.1 history_fname = common.prog_name+'.history'
418     history_file = open(history_fname, 'a')
419     history_file.write(self.current_time+': '+args+'\n')
420     history_file.close()
421     return
422    
423 nsmirnov 1.3 def headerString_(self):
424 nsmirnov 1.1 """
425     Creates a string describing program options either given in
426     the command line or their default values.
427     """
428     header = common.prog_name + ' (version ' + common.prog_version_str + \
429     ') running on ' + \
430     time.ctime(time.time())+'\n\n' + \
431     common.prog_name+'. Working options:\n'
432     header = header +\
433     ' scheduler ' + self.scheduler_name + '\n'+\
434     ' job type ' + self.job_type_name + '\n'+\
435     ' working directory ' + common.work_space.topDir()\
436     + '\n'
437     return header
438    
439 nsmirnov 1.3 def createScheduler_(self):
440 nsmirnov 1.1 """
441     Creates a scheduler object instantiated by its name.
442     """
443     klass_name = 'Scheduler' + string.capitalize(self.scheduler_name)
444     file_name = klass_name
445     try:
446     klass = importName(file_name, klass_name)
447     except KeyError:
448     msg = 'No `class '+klass_name+'` found in file `'+file_name+'.py`'
449     raise CrabException(msg)
450     except ImportError, e:
451     msg = 'Cannot create scheduler '+self.scheduler_name
452     msg += ' (file: '+file_name+', class '+klass_name+'):\n'
453     msg += str(e)
454     raise CrabException(msg)
455    
456     common.scheduler = klass()
457     common.scheduler.configure(self.cfg_params)
458     return
459    
460     def run(self):
461     """
462     For each
463     """
464    
465     for act in self.main_actions:
466     if act in self.actions.keys(): self.actions[act].run()
467     pass
468    
469     for act in self.aux_actions:
470     if act in self.actions.keys(): self.actions[act].run()
471     pass
472     return
473    
474     ###########################################################################
475     def processHelpOptions(opts):
476    
477     for opt in opts.keys():
478     if opt == '-v':
479     print Crab().version()
480     return 1
481     if opt in ('-h','-help','--help') :
482     if opts[opt] : help(opts[opt])
483     else: help()
484     return 1
485    
486     return 0
487    
488     ###########################################################################
489     if __name__ == '__main__':
490    
491     # Parse command-line options and create a dictionary with
492     # key-value pairs.
493    
494     options = parseOptions(sys.argv[1:])
495    
496     # Process "help" options, such as '-help', '-version'
497    
498     if processHelpOptions(options): sys.exit(0)
499    
500     # Create, initialize, and run a Crab object
501    
502     try:
503 nsmirnov 1.3 crab = Crab(options)
504 nsmirnov 1.1 crab.run()
505     except CrabException, e:
506     print '\n' + common.prog_name + ': ' + str(e) + '\n'
507     if common.logger:
508     common.logger.write('ERROR: '+str(e)+'\n')
509     pass
510     pass
511    
512     pass