ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/COMP/CRAB/python/crab.py
Revision: 1.24
Committed: Wed Oct 19 14:44:50 2005 UTC (19 years, 6 months ago) by slacapra
Content type: text/x-python
Branch: MAIN
Changes since 1.23: +19 -8 lines
Log Message:
fixing stuff for submit

File Contents

# User Rev Content
1 slacapra 1.9 #!/usr/bin/env python2.2
2 nsmirnov 1.1 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 slacapra 1.8 from Checker import Checker
12 slacapra 1.9 from PostMortem import PostMortem
13     from Status import Status
14 spiga 1.16 from StatusBoss import StatusBoss
15 nsmirnov 1.1 import common
16 spiga 1.13 import Statistic
17 nsmirnov 1.1
18     import sys, os, time, string
19    
20     ###########################################################################
21     class Crab:
22 nsmirnov 1.3 def __init__(self, opts):
23 nsmirnov 1.1
24     # The order of main_actions is important !
25 slacapra 1.9 self.main_actions = [ '-create', '-submit', '-monitor' ]
26 slacapra 1.8 self.aux_actions = [ '-list', '-kill', '-status', '-getoutput',
27 slacapra 1.9 '-resubmit' , '-cancelAndResubmit', '-check', '-postMortem', '-clean']
28 nsmirnov 1.1
29     # Dictionary of actions, e.g. '-create' -> object of class Creator
30     self.actions = {}
31    
32     # Configuration file
33     self.cfg_fname = None
34     # Dictionary with configuration parameters
35     self.cfg_params = {}
36    
37     # Current working directory
38     self.cwd = os.getcwd()+'/'
39     # Current time in format 'yymmdd_hhmmss'
40     self.current_time = time.strftime('%y%m%d_%H%M%S',
41     time.localtime(time.time()))
42    
43 nsmirnov 1.3 # Session name (?) Do we need this ?
44 nsmirnov 1.1 self.name = '0'
45    
46     # Job type
47     self.job_type_name = None
48    
49     # Continuation flag
50     self.flag_continue = 0
51    
52     # quiet mode, i.e. no output on screen
53     self.flag_quiet = 0
54     # produce more output
55     self.debug_level = 0
56    
57 nsmirnov 1.3 # Scheduler name, e.g. 'edg', 'lsf'
58 fanzago 1.14 self.scheduler_name = ''
59 nsmirnov 1.1
60 nsmirnov 1.3 self.initialize_(opts)
61 nsmirnov 1.1
62     return
63    
64 nsmirnov 1.7 def version():
65 nsmirnov 1.1 return common.prog_version_str
66    
67 nsmirnov 1.7 version = staticmethod(version)
68    
69 nsmirnov 1.3 def initialize_(self, opts):
70 nsmirnov 1.1
71     # Process the '-continue' option first because
72     # in the case of continuation the CRAB configuration
73     # parameters are loaded from already existing Working Space.
74 nsmirnov 1.3 self.processContinueOption_(opts)
75 nsmirnov 1.1
76     # Process ini-file first, then command line options
77     # because they override ini-file settings.
78    
79 nsmirnov 1.3 self.processIniFile_(opts)
80 nsmirnov 1.1
81 nsmirnov 1.3 if self.flag_continue: opts = self.loadConfiguration_(opts)
82 nsmirnov 1.1
83 nsmirnov 1.3 self.processOptions_(opts)
84 nsmirnov 1.1
85     if not self.flag_continue:
86 nsmirnov 1.3 self.createWorkingSpace_()
87 slacapra 1.9 optsToBeSaved={}
88     for it in opts.keys():
89     if (it in self.main_actions) or (it in self.aux_actions) or (it == '-debug'):
90     pass
91     else:
92     optsToBeSaved[it]=opts[it]
93     common.work_space.saveConfiguration(optsToBeSaved, self.cfg_fname)
94 nsmirnov 1.1 pass
95    
96     # At this point all configuration options have been read.
97    
98     args = string.join(sys.argv,' ')
99 slacapra 1.11
100 nsmirnov 1.3 self.updateHistory_(args)
101 slacapra 1.11
102 nsmirnov 1.3 self.createLogger_(args)
103 slacapra 1.11
104 nsmirnov 1.1 common.jobDB = JobDB()
105 slacapra 1.11
106 nsmirnov 1.3 if self.flag_continue:
107 slacapra 1.12 try:
108     common.jobDB.load()
109     common.logger.debug(6, str(common.jobDB))
110     except DBException,e:
111     pass
112 nsmirnov 1.3 pass
113 slacapra 1.11
114 nsmirnov 1.3 self.createScheduler_()
115 slacapra 1.11
116 nsmirnov 1.3 if common.logger.debugLevel() >= 6:
117     common.logger.debug(6, 'Used properties:')
118     keys = self.cfg_params.keys()
119     keys.sort()
120     for k in keys:
121     if self.cfg_params[k]:
122     common.logger.debug(6, ' '+k+' : '+self.cfg_params[k])
123     pass
124     else:
125     common.logger.debug(6, ' '+k+' : ')
126     pass
127     pass
128     common.logger.debug(6, 'End of used properties.\n')
129     pass
130     self.initializeActions_(opts)
131 nsmirnov 1.1 return
132    
133 nsmirnov 1.3 def processContinueOption_(self,opts):
134 nsmirnov 1.1
135     continue_dir = None
136 nsmirnov 1.4
137     # Look for the '-continue' option.
138    
139 nsmirnov 1.1 for opt in opts.keys():
140     if ( opt in ('-continue','-c') ):
141     self.flag_continue = 1
142     val = opts[opt]
143     if val:
144     if val[0] == '/': continue_dir = val # abs path
145     else: continue_dir = self.cwd + val # rel path
146     pass
147 nsmirnov 1.4 break
148     pass
149    
150     # Look for actions which has sense only with '-continue'
151    
152     if not self.flag_continue:
153     for opt in opts.keys():
154 slacapra 1.6 if ( opt in (self.aux_actions) ):
155 nsmirnov 1.4 self.flag_continue = 1
156     break
157 nsmirnov 1.1 pass
158     pass
159 slacapra 1.6 submit_flag=0
160     create_flag=0
161     for opt in opts.keys():
162     if opt == "-submit": submit_flag=1
163     if opt == "-create": create_flag=1
164     pass
165     if (submit_flag and not create_flag):
166 nsmirnov 1.7 msg = "'-submit' must be used with either '-create' or '-continue'."
167     raise CrabException(msg)
168 slacapra 1.6 pass
169 nsmirnov 1.1
170     if not self.flag_continue: return
171    
172     if not continue_dir:
173     prefix = common.prog_name + '_' + self.name + '_'
174     continue_dir = findLastWorkDir(prefix)
175     pass
176    
177     if not continue_dir:
178     raise CrabException('Cannot find last working directory.')
179    
180     if not os.path.exists(continue_dir):
181     msg = 'Cannot continue because the working directory <'
182     msg += continue_dir
183     msg += '> does not exist.'
184     raise CrabException(msg)
185    
186     # Instantiate WorkSpace
187     common.work_space = WorkSpace(continue_dir)
188    
189     return
190    
191 nsmirnov 1.3 def processIniFile_(self, opts):
192 nsmirnov 1.1 """
193     Processes a configuration INI-file.
194     """
195    
196     # Extract cfg-file name from the cmd-line options.
197    
198     for opt in opts.keys():
199     if ( opt == '-cfg' ):
200     if self.flag_continue:
201     raise CrabException('-continue and -cfg cannot coexist.')
202     if opts[opt] : self.cfg_fname = opts[opt]
203     else : usage()
204     pass
205    
206     elif ( opt == '-name' ):
207     self.name = opts[opt]
208     pass
209    
210     pass
211    
212     # Set default cfg-fname
213    
214     if self.cfg_fname == None:
215     if self.flag_continue:
216     self.cfg_fname = common.work_space.cfgFileName()
217     else:
218     self.cfg_fname = common.prog_name+'.cfg'
219     pass
220     pass
221    
222     # Load cfg-file
223    
224     if string.lower(self.cfg_fname) != 'none':
225     if os.path.exists(self.cfg_fname):
226     self.cfg_params = loadConfig(self.cfg_fname)
227     pass
228     else:
229     msg = 'cfg-file '+self.cfg_fname+' not found.'
230     raise CrabException(msg)
231     pass
232     pass
233    
234     # process the [CRAB] section
235    
236     lhp = len('CRAB.')
237     for k in self.cfg_params.keys():
238     if len(k) >= lhp and k[:lhp] == 'CRAB.':
239     opt = '-'+k[lhp:]
240     if len(opt) >= 3 and opt[:3] == '-__': continue
241     if opt not in opts.keys():
242     opts[opt] = self.cfg_params[k]
243     pass
244     pass
245     pass
246    
247     return
248    
249 nsmirnov 1.3 def processOptions_(self, opts):
250 nsmirnov 1.1 """
251     Processes the command-line options.
252     """
253    
254     for opt in opts.keys():
255     val = opts[opt]
256    
257 nsmirnov 1.3 # Skip actions, they are processed later in initializeActions_()
258     if opt in self.main_actions:
259     self.cfg_params['CRAB.'+opt[1:]] = val
260     continue
261     if opt in self.aux_actions:
262     self.cfg_params['CRAB.'+opt[1:]] = val
263     continue
264 nsmirnov 1.1
265    
266     elif ( opt == '-cfg' ):
267     pass
268    
269     elif ( opt in ('-continue', '-c') ):
270 nsmirnov 1.4 # Already processed in processContinueOption_()
271 nsmirnov 1.1 pass
272    
273     elif ( opt == '-jobtype' ):
274     if val : self.job_type_name = string.upper(val)
275     else : usage()
276     pass
277    
278     elif ( opt == '-Q' ):
279     self.flag_quiet = 1
280     pass
281    
282     elif ( opt == '-debug' ):
283 slacapra 1.6 if val: self.debug_level = int(val)
284     else: self.debug_level = 1
285 nsmirnov 1.1 pass
286    
287     elif ( opt == '-scheduler' ):
288     if val: self.scheduler_name = val
289     else:
290     print common.prog_name+". No value for '-scheduler'."
291     usage()
292     pass
293     pass
294 slacapra 1.22
295 fanzago 1.18 elif ( opt in ('-use_boss', '-useboss') ):
296     if ( val == '1' ):
297     self.scheduler_name = 'boss'
298     pass
299     elif ( val == '0' ):
300     pass
301     else:
302     print common.prog_name+'. Bad flag for -use_boss option:',\
303     val,'Possible values are 0(=No) or 1(=Yes)'
304     usage()
305     pass
306 fanzago 1.14 pass
307    
308 nsmirnov 1.3 elif string.find(opt,'.') == -1:
309     print common.prog_name+'. Unrecognized option '+opt
310     usage()
311     pass
312 nsmirnov 1.1
313 nsmirnov 1.3 # Override config parameters from INI-file with cmd-line params
314     if string.find(opt,'.') == -1 :
315     self.cfg_params['CRAB.'+opt[1:]] = val
316 nsmirnov 1.1 pass
317 nsmirnov 1.3 else:
318 nsmirnov 1.1 # Command line parameters in the form -SECTION.ENTRY=VALUE
319     self.cfg_params[opt[1:]] = val
320     pass
321     pass
322     return
323    
324 slacapra 1.8 def parseRange_(self, aRange):
325 nsmirnov 1.4 """
326 slacapra 1.8 Takes as the input a string with a range defined in any of the following
327     way, including combination, and return a tuple with the ints defined
328     according to following table. A consistency check is done.
329     NB: the first job is "1", not "0".
330     'all' -> [1,2,..., NJobs]
331     '' -> [1,2,..., NJobs]
332     'n1' -> [n1]
333     'n1-n2' -> [n1, n1+1, n1+2, ..., n2-1, n2]
334     'n1,n2' -> [n1, n2]
335     'n1,n2-n3' -> [n1, n2, n2+1, n2+2, ..., n3-1, n3]
336     """
337     result = []
338    
339 slacapra 1.9 common.logger.debug(5,"parseRange_ "+str(aRange))
340     if aRange=='all' or aRange==None or aRange=='':
341 slacapra 1.8 result=range(0,common.jobDB.nJobs())
342     return result
343 slacapra 1.9 elif aRange=='0':
344     return result
345 slacapra 1.8
346     subRanges = string.split(aRange, ',')
347     for subRange in subRanges:
348     result = result+self.parseSimpleRange_(subRange)
349    
350     if self.checkUniqueness_(result):
351     return result
352     else:
353     print "Error ", result
354     return []
355    
356     def checkUniqueness_(self, list):
357     """
358 slacapra 1.9 check if a list contains only unique elements
359 slacapra 1.8 """
360    
361     uniqueList = []
362     # use a list comprehension statement (takes a while to understand)
363    
364     [uniqueList.append(it) for it in list if not uniqueList.count(it)]
365    
366     return (len(list)==len(uniqueList))
367    
368     def parseSimpleRange_(self, aRange):
369     """
370     Takes as the input a string with two integers separated by
371     the minus sign and returns the tuple with these numbers:
372     'n1-n2' -> [n1, n1+1, n1+2, ..., n2-1, n2]
373     'n1' -> [n1]
374     """
375     (start, end) = (None, None)
376    
377     result = []
378     minus = string.find(aRange, '-')
379     if ( minus < 0 ):
380     if isInt(aRange) and int(aRange)>0:
381     result.append(int(aRange)-1)
382     else:
383 slacapra 1.9 common.logger.message("parseSimpleRange_ ERROR "+aRange)
384 nsmirnov 1.4 pass
385     else:
386 slacapra 1.8 (start, end) = string.split(aRange, '-')
387     if isInt(start) and isInt(end) and int(start)>0 and int(start)<int(end):
388     result=range(int(start)-1, int(end))
389     else:
390     print "ERROR ", start, end
391    
392     return result
393 nsmirnov 1.4
394 nsmirnov 1.3 def initializeActions_(self, opts):
395 nsmirnov 1.1 """
396     For each user action instantiate a corresponding
397     object and put it in the action dictionary.
398     """
399     for opt in opts.keys():
400 spiga 1.16 if ( opt == '-use_boss'):
401 spiga 1.15 self.flag_useboss = 1
402     else:
403     self.flag_useboss = 0
404     pass
405    
406     for opt in opts.keys():
407    
408 nsmirnov 1.1 val = opts[opt]
409 spiga 1.15
410    
411     if ( opt == '-create' ):
412 slacapra 1.22 ncjobs = 0
413 nsmirnov 1.1 if val:
414     if ( isInt(val) ):
415     ncjobs = int(val)
416     elif ( val == 'all'):
417     ncjobs = val
418     else:
419 nsmirnov 1.5 msg = 'Bad creation bunch size <'+str(val)+'>\n'
420     msg += ' Must be an integer or "all"'
421 slacapra 1.8 msg += ' Generic range is not allowed"'
422 nsmirnov 1.5 raise CrabException(msg)
423 nsmirnov 1.1 pass
424     else: ncjobs = 'all'
425    
426     if ncjobs != 0:
427 nsmirnov 1.3 # Instantiate Creator object
428 nsmirnov 1.1 creator = Creator(self.job_type_name,
429     self.cfg_params,
430     ncjobs)
431     self.actions[opt] = creator
432 nsmirnov 1.3
433     # Initialize the JobDB object if needed
434 nsmirnov 1.1 if not self.flag_continue:
435     common.jobDB.create(creator.nJobs())
436     pass
437 nsmirnov 1.3
438     # Create and initialize JobList
439    
440     common.job_list = JobList(common.jobDB.nJobs(),
441     creator.jobType())
442    
443     common.job_list.setScriptNames(self.job_type_name+'.sh')
444     common.job_list.setJDLNames(self.job_type_name+'.jdl')
445 slacapra 1.12 common.job_list.setCfgNames(self.job_type_name+'.orcarc')
446 slacapra 1.9
447     creator.writeJobsSpecsToDB()
448 nsmirnov 1.1 pass
449 nsmirnov 1.3 pass
450 nsmirnov 1.1
451     elif ( opt == '-submit' ):
452 slacapra 1.23
453     # total jobs
454     # get the first not already submitted
455 slacapra 1.24 common.logger.debug(5,'Total jobs '+str(common.jobDB.nJobs()))
456     lastSubmittedJob=0
457     for nj in range(common.jobDB.nJobs()):
458     if (common.jobDB.status(nj)=='S'):
459     lastSubmittedJob +=1
460 slacapra 1.23 else: break
461 slacapra 1.24 # count job from 1
462     totalJobsSubmittable = common.jobDB.nJobs()-lastSubmittedJob
463     common.logger.debug(5,'lastSubmittedJob '+str(lastSubmittedJob))
464     common.logger.debug(5,'totalJobsSubmittable '+str(totalJobsSubmittable))
465 slacapra 1.23
466 slacapra 1.24 nsjobs = lastSubmittedJob+totalJobsSubmittable
467 slacapra 1.23 # get user request
468 slacapra 1.22 if val:
469     if ( isInt(val) ):
470 slacapra 1.24 tmp = int(val)
471     if (tmp >= totalJobsSubmittable):
472     common.logger.message('asking to submit '+str(tmp)+' jobs, but only '+str(totalJobsSubmittable)+' left: submitting those')
473     pass
474     else:
475     nsjobs=lastSubmittedJob+int(val)
476 slacapra 1.23 elif (val=='all'):
477     pass
478 slacapra 1.22 else:
479     msg = 'Bad submission option <'+str(val)+'>\n'
480     msg += ' Must be an integer or "all"'
481     msg += ' Generic range is not allowed"'
482     raise CrabException(msg)
483     pass
484 slacapra 1.24 common.logger.debug(5,'nsjobs '+str(nsjobs))
485 slacapra 1.23
486     # submit N from last submitted job
487 slacapra 1.24 nj_list = range(lastSubmittedJob, nsjobs)
488     common.logger.debug(5,'nj_list '+str(nj_list))
489 nsmirnov 1.5
490     if len(nj_list) != 0:
491 nsmirnov 1.3 # Instantiate Submitter object
492 nsmirnov 1.5 self.actions[opt] = Submitter(self.cfg_params, nj_list)
493 nsmirnov 1.3
494     # Create and initialize JobList
495     if len(common.job_list) == 0 :
496     common.job_list = JobList(common.jobDB.nJobs(),
497     None)
498     common.job_list.setJDLNames(self.job_type_name+'.jdl')
499     pass
500 nsmirnov 1.1 pass
501 nsmirnov 1.3 pass
502 nsmirnov 1.1
503 nsmirnov 1.4 elif ( opt == '-list' ):
504 slacapra 1.8 jobs = self.parseRange_(val)
505    
506     common.jobDB.dump(jobs)
507 nsmirnov 1.4 pass
508    
509     elif ( opt == '-status' ):
510 slacapra 1.8 jobs = self.parseRange_(val)
511    
512 slacapra 1.9 if len(jobs) != 0:
513 spiga 1.16 if ( self.flag_useboss == 1 ):
514     self.actions[opt] = StatusBoss(self.cfg_params, jobs)
515 spiga 1.15 else:
516     # Instantiate Submitter object
517     self.actions[opt] = Status(self.cfg_params, jobs)
518     pass
519 nsmirnov 1.1 pass
520     pass
521 slacapra 1.22
522 nsmirnov 1.4 elif ( opt == '-kill' ):
523 slacapra 1.9 if val:
524     jobs = self.parseRange_(val)
525 slacapra 1.8
526 slacapra 1.9 for nj in jobs:
527     st = common.jobDB.status(nj)
528     if st == 'S':
529     jid = common.jobDB.jobId(nj)
530     common.logger.message("Killing job # "+`(nj+1)`)
531     common.scheduler.cancel(jid)
532     common.jobDB.setStatus(nj, 'K')
533     pass
534 nsmirnov 1.4 pass
535 slacapra 1.9
536     common.jobDB.save()
537 nsmirnov 1.1 pass
538 slacapra 1.9 else:
539     common.logger.message("Warning: with '-kill' you _MUST_ specify a job range or 'all'")
540 nsmirnov 1.1
541 slacapra 1.8 elif ( opt == '-getoutput' ):
542    
543 spiga 1.20 if ( self.flag_useboss == 1 ):
544     if val=='all' or val==None or val=='':
545 spiga 1.21 jobs = common.scheduler.listBoss()
546 spiga 1.20 else:
547     jobs = self.parseRange_(val)
548    
549     common.scheduler.getOutput(jobs)
550     else:
551 slacapra 1.22 ## This should not be here.
552 spiga 1.20 jobs = self.parseRange_(val)
553     fileCODE1 = open(common.work_space.logDir()+"/.code","r")
554     array = fileCODE1.read().split('::')
555     self.ID1 = array[0]
556     self.NJC = array[1]
557     self.dataset = array[2]
558     self.owner = array[3]
559     fileCODE1.close()
560 slacapra 1.22 ###
561 spiga 1.13
562 slacapra 1.22 ## also this: create a ActorClass (GetOutput)
563 spiga 1.20 jobs_done = []
564     for nj in jobs:
565     st = common.jobDB.status(nj)
566     if st == 'D':
567 slacapra 1.12 jobs_done.append(nj)
568 spiga 1.20 pass
569     elif st == 'S':
570     jid = common.jobDB.jobId(nj)
571     currStatus = common.scheduler.queryStatus(jid)
572     if currStatus=="Done":
573     jobs_done.append(nj)
574     else:
575     msg = 'Job # '+`(nj+1)`+' submitted but still status '+currStatus+' not possible to get output'
576     common.logger.message(msg)
577     pass
578 slacapra 1.9 else:
579 spiga 1.20 # common.logger.message('Jobs #'+`(nj+1)`+' has status '+st+' not possible to get output')
580     pass
581 slacapra 1.12 pass
582    
583 spiga 1.20 for nj in jobs_done:
584 spiga 1.15 jid = common.jobDB.jobId(nj)
585     dir = common.scheduler.getOutput(jid)
586     common.jobDB.setStatus(nj, 'Y')
587 slacapra 1.12
588     # Rename the directory with results to smth readable
589     new_dir = common.work_space.resDir()
590 spiga 1.20 try:
591     files = os.listdir(dir)
592     for file in files:
593     os.rename(dir+'/'+file, new_dir+'/'+file)
594     os.rmdir(dir)
595     except OSError, e:
596     msg = 'rename files from '+dir+' to '+new_dir+' error: '
597     msg += str(e)
598     common.logger.message(msg)
599     # ignore error
600 slacapra 1.12 pass
601 spiga 1.20 pass
602 slacapra 1.22 ###
603    
604     ## again, this should not be here but in getoutput class
605 spiga 1.13 destination = common.scheduler.queryDest(jid).split(":")[0]
606     ID3 = jid.split("/")[3]
607     broker = jid.split("/")[2].split(":")[0]
608     resFlag = 0
609     exCode = common.scheduler.getExitStatus(jid)
610     Statistic.notify('retrieved',resFlag,exCode,self.dataset,self.owner,destination,broker,ID3,self.ID1,self.NJC)
611 slacapra 1.22 ###
612 slacapra 1.12
613     msg = 'Results of Job # '+`(nj+1)`+' are in '+new_dir
614     common.logger.message(msg)
615 nsmirnov 1.4 pass
616    
617     common.jobDB.save()
618     pass
619    
620     elif ( opt == '-resubmit' ):
621 slacapra 1.11 if val:
622     jobs = self.parseRange_(val)
623 slacapra 1.8
624 slacapra 1.11 # create a list of jobs to be resubmitted.
625 slacapra 1.8
626 slacapra 1.22 ### as before, create a Resubmittter Class
627 slacapra 1.11 nj_list = []
628     for nj in jobs:
629     st = common.jobDB.status(nj)
630 slacapra 1.8
631 slacapra 1.11 if st in ['K','A']:
632     nj_list.append(nj)
633     elif st == 'Y':
634     # here I would like to move the old output to a new place
635     # I would need the name of the output files.
636     # these infos are in the jobType class, which is not accessible from here!
637     outSandbox = common.jobDB.outputSandbox(nj)
638    
639     resDir = common.work_space.resDir()
640     resDirSave = resDir + self.current_time
641     os.mkdir(resDirSave)
642    
643     for file in outSandbox:
644     if os.path.exists(resDir+'/'+file):
645     os.rename(resDir+'/'+file, resDirSave+'/'+file)
646     common.logger.message('Output file '+file+' moved to '+resDirSave)
647     pass
648     nj_list.append(nj)
649 spiga 1.13 st = common.jobDB.setStatus(nj,'RC')
650 slacapra 1.11 elif st == 'D':
651     ## Done but not yet retrieved
652     ## retrieve job, then go to previous ('Y') case
653     ## TODO
654     pass
655     else:
656     common.logger.message('Job #'+str(nj+1)+' has status '+crabJobStatusToString(st)+' must be "killed" before resubmission')
657 slacapra 1.9 pass
658 slacapra 1.8
659 slacapra 1.11 if len(nj_list) != 0:
660     # Instantiate Submitter object
661     self.actions[opt] = Submitter(self.cfg_params, nj_list)
662    
663     # Create and initialize JobList
664    
665     if len(common.job_list) == 0 :
666     common.job_list = JobList(common.jobDB.nJobs(),
667     None)
668     common.job_list.setJDLNames(self.job_type_name+'.jdl')
669     pass
670 slacapra 1.8 pass
671     pass
672 slacapra 1.11 else:
673     common.logger.message("Warning: with '-resubmit' you _MUST_ specify a job range or 'all'")
674     common.logger.message("WARNING: _all_ job specified in the rage will be resubmitted!!!")
675     pass
676 slacapra 1.8 pass
677    
678     elif ( opt == '-cancelAndResubmit' ):
679     jobs = self.parseRange_(val)
680 nsmirnov 1.5
681 nsmirnov 1.7 # Cancel submitted jobs.
682 nsmirnov 1.5
683 slacapra 1.8 nj_list = []
684     for nj in jobs:
685 nsmirnov 1.5 st = common.jobDB.status(nj)
686     if st == 'S':
687     jid = common.jobDB.jobId(nj)
688     common.scheduler.cancel(jid)
689     st = 'K'
690     common.jobDB.setStatus(nj, st)
691     pass
692 nsmirnov 1.7 pass
693 nsmirnov 1.5
694 slacapra 1.8 if st != 'X': nj_list.append(nj)
695     pass
696 nsmirnov 1.5
697     if len(nj_list) != 0:
698     # Instantiate Submitter object
699     self.actions[opt] = Submitter(self.cfg_params, nj_list)
700    
701     # Create and initialize JobList
702    
703     if len(common.job_list) == 0 :
704     common.job_list = JobList(common.jobDB.nJobs(),
705     None)
706     common.job_list.setJDLNames(self.job_type_name+'.jdl')
707     pass
708     pass
709 nsmirnov 1.4 pass
710    
711 slacapra 1.8 elif ( opt == '-check' ):
712     jobs = self.parseRange_(val)
713     nj_list = []
714     for nj in jobs:
715     st = common.jobDB.status(nj)
716 slacapra 1.12 if st == 'C': nj_list.append(nj)
717 slacapra 1.8 pass
718    
719     if len(nj_list) != 0:
720     # Instantiate Submitter object
721     self.actions[opt] = Checker(self.cfg_params, nj_list)
722    
723     # Create and initialize JobList
724    
725     if len(common.job_list) == 0 :
726     common.job_list = JobList(common.jobDB.nJobs(), None)
727     common.job_list.setJDLNames(self.job_type_name+'.jdl')
728     pass
729     pass
730    
731 slacapra 1.9 elif ( opt == '-postMortem' ):
732     jobs = self.parseRange_(val)
733     nj_list = []
734     for nj in jobs:
735     st = common.jobDB.status(nj)
736 fanzago 1.17 if st not in ['X', 'C']: nj_list.append(nj)
737 slacapra 1.9 pass
738    
739     if len(nj_list) != 0:
740     # Instantiate Submitter object
741     self.actions[opt] = PostMortem(self.cfg_params, nj_list)
742    
743     # Create and initialize JobList
744    
745     if len(common.job_list) == 0 :
746     common.job_list = JobList(common.jobDB.nJobs(), None)
747     common.job_list.setJDLNames(self.job_type_name+'.jdl')
748     pass
749     pass
750    
751     elif ( opt == '-clean' ):
752     if val != None:
753     raise CrabException("No range allowed for '-clean'")
754    
755     submittedJobs=0
756 slacapra 1.11 doneJobs=0
757 slacapra 1.12 try:
758     for nj in range(0,common.jobDB.nJobs()):
759     st = common.jobDB.status(nj)
760     if st == 'S':
761     submittedJobs = submittedJobs+1
762     if st == 'D':
763     doneJobs = doneJobs+1
764     pass
765     pass
766     except DBException:
767     common.logger.debug(5,'DB not found, so delete all')
768 nsmirnov 1.1 pass
769 slacapra 1.9
770 slacapra 1.11 if submittedJobs or doneJobs:
771     msg = "There are still "
772     if submittedJobs:
773     msg= msg+str(submittedJobs)+" jobs submitted. Kill them '-kill' before '-clean'"
774     if (submittedJobs and doneJobs):
775     msg = msg + "and \nalso"
776     if doneJobs:
777     msg= msg+str(doneJobs)+" jobs Done. Get their outputs '-getoutput' before '-clean'"
778     raise CrabException(msg)
779 slacapra 1.9
780     msg = 'directory '+common.work_space.topDir()+' removed'
781     common.work_space.delete()
782     common.logger.message(msg)
783    
784 nsmirnov 1.1 pass
785 slacapra 1.9
786 nsmirnov 1.1 pass
787     return
788    
789 nsmirnov 1.3 def createWorkingSpace_(self):
790 slacapra 1.9 new_dir = ''
791    
792     try:
793     new_dir = self.cfg_params['USER.ui_working_dir']
794     except KeyError:
795     new_dir = common.prog_name + '_' + self.name + '_' + self.current_time
796     new_dir = self.cwd + new_dir
797     pass
798    
799 nsmirnov 1.1 common.work_space = WorkSpace(new_dir)
800     common.work_space.create()
801     return
802    
803 nsmirnov 1.3 def loadConfiguration_(self, opts):
804 nsmirnov 1.1
805     save_opts = common.work_space.loadSavedOptions()
806    
807     # Override saved options with new command-line options
808    
809     for k in opts.keys():
810     save_opts[k] = opts[k]
811     pass
812    
813     # Return updated options
814     return save_opts
815    
816 nsmirnov 1.3 def createLogger_(self, args):
817 nsmirnov 1.1
818     log = Logger()
819     log.quiet(self.flag_quiet)
820     log.setDebugLevel(self.debug_level)
821     log.write(args+'\n')
822 nsmirnov 1.3 log.message(self.headerString_())
823 nsmirnov 1.1 log.flush()
824     common.logger = log
825     return
826    
827 nsmirnov 1.3 def updateHistory_(self, args):
828 nsmirnov 1.1 history_fname = common.prog_name+'.history'
829     history_file = open(history_fname, 'a')
830     history_file.write(self.current_time+': '+args+'\n')
831     history_file.close()
832     return
833    
834 nsmirnov 1.3 def headerString_(self):
835 nsmirnov 1.1 """
836     Creates a string describing program options either given in
837     the command line or their default values.
838     """
839     header = common.prog_name + ' (version ' + common.prog_version_str + \
840     ') running on ' + \
841     time.ctime(time.time())+'\n\n' + \
842     common.prog_name+'. Working options:\n'
843     header = header +\
844     ' scheduler ' + self.scheduler_name + '\n'+\
845     ' job type ' + self.job_type_name + '\n'+\
846     ' working directory ' + common.work_space.topDir()\
847     + '\n'
848     return header
849    
850 nsmirnov 1.3 def createScheduler_(self):
851 nsmirnov 1.1 """
852     Creates a scheduler object instantiated by its name.
853     """
854     klass_name = 'Scheduler' + string.capitalize(self.scheduler_name)
855     file_name = klass_name
856     try:
857     klass = importName(file_name, klass_name)
858     except KeyError:
859     msg = 'No `class '+klass_name+'` found in file `'+file_name+'.py`'
860     raise CrabException(msg)
861     except ImportError, e:
862     msg = 'Cannot create scheduler '+self.scheduler_name
863     msg += ' (file: '+file_name+', class '+klass_name+'):\n'
864     msg += str(e)
865     raise CrabException(msg)
866    
867     common.scheduler = klass()
868     common.scheduler.configure(self.cfg_params)
869     return
870    
871     def run(self):
872     """
873     For each
874     """
875    
876     for act in self.main_actions:
877     if act in self.actions.keys(): self.actions[act].run()
878     pass
879    
880     for act in self.aux_actions:
881     if act in self.actions.keys(): self.actions[act].run()
882     pass
883     return
884    
885     ###########################################################################
886     def processHelpOptions(opts):
887    
888 slacapra 1.11 if len(opts):
889     for opt in opts.keys():
890     if opt in ('-v', '-version', '--version') :
891     print Crab.version()
892     return 1
893     if opt in ('-h','-help','--help') :
894     if opts[opt] : help(opts[opt])
895     else: help()
896     return 1
897     else:
898     usage()
899 nsmirnov 1.1
900     return 0
901    
902     ###########################################################################
903     if __name__ == '__main__':
904    
905 fanzago 1.18
906 fanzago 1.19 # # Initial settings for Python modules. Avoid appending manually lib paths.
907     # try:
908     # path=os.environ['EDG_WL_LOCATION']
909     # except:
910     # print "Error: Please set the EDG_WL_LOCATION environment variable pointing to the userinterface installation path"
911     # sys.exit(1)
912     #
913     # libPath=os.path.join(path, "lib")
914     # sys.path.append(libPath)
915     # libPath=os.path.join(path, "lib", "python")
916     # sys.path.append(libPath)
917 fanzago 1.18
918    
919 nsmirnov 1.1 # Parse command-line options and create a dictionary with
920     # key-value pairs.
921    
922     options = parseOptions(sys.argv[1:])
923    
924     # Process "help" options, such as '-help', '-version'
925    
926 slacapra 1.11 if processHelpOptions(options) : sys.exit(0)
927 nsmirnov 1.1
928     # Create, initialize, and run a Crab object
929    
930     try:
931 nsmirnov 1.3 crab = Crab(options)
932 nsmirnov 1.1 crab.run()
933     except CrabException, e:
934     print '\n' + common.prog_name + ': ' + str(e) + '\n'
935     if common.logger:
936     common.logger.write('ERROR: '+str(e)+'\n')
937     pass
938     pass
939    
940     pass