ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/COMP/CRAB/python/crab_util.py
Revision: 1.38
Committed: Wed Feb 13 18:17:54 2008 UTC (17 years, 2 months ago) by slacapra
Content type: text/x-python
Branch: MAIN
CVS Tags: CRAB_2_1_2, CRAB_2_1_2_pre2, CRAB_2_1_2_pre1, CRAB_2_1_1, CRAB_2_1_1_pre3, CRAB_2_1_1_pre1, CRAB_2_1_0, CRAB_2_1_0_pre6, CRAB_2_1_0_pre5
Branch point for: CRAB_2_1_2_br, CRAB_2_1_1_pre2
Changes since 1.37: +2 -0 lines
Log Message:
Fix problem in resubmission when passing a parameter the number of the job you want to resubmit
eg -resubmit 4
now means (as was before) to resubmit job #4, not to resubmit 4 jobs.
Create a new class Resubmitter (derived from Submitter) to deal with the logic of selecting the job to be resubmitetd from the user request and job status. This clean up a bit crab.py
The actual submission is always done by Submitter::run()

File Contents

# User Rev Content
1 nsmirnov 1.1 ###########################################################################
2     #
3     # C O N V E N I E N C E F U N C T I O N S
4     #
5     ###########################################################################
6    
7 slacapra 1.12 import string, sys, os, time
8 slacapra 1.16 import ConfigParser, re, popen2, select, fcntl
9 nsmirnov 1.1
10 nsmirnov 1.2 import common
11 slacapra 1.30 from crab_exceptions import CrabException
12 nsmirnov 1.1
13     ###########################################################################
14     def parseOptions(argv):
15     """
16     Parses command-line options.
17     Returns a dictionary with specified options as keys:
18     -opt1 --> 'opt1' : None
19     -opt2 val --> 'opt2' : 'val'
20     -opt3=val --> 'opt3' : 'val'
21     Usually called as
22     options = parseOptions(sys.argv[1:])
23     """
24     options = {}
25     argc = len(argv)
26     i = 0
27     while ( i < argc ):
28     if argv[i][0] != '-':
29     i = i + 1
30     continue
31     eq = string.find(argv[i], '=')
32     if eq > 0 :
33     opt = argv[i][:eq]
34     val = argv[i][eq+1:]
35     pass
36     else:
37     opt = argv[i]
38     val = None
39     if ( i+1 < argc and argv[i+1][0] != '-' ):
40     i = i + 1
41     val = argv[i]
42     pass
43     pass
44     options[opt] = val
45     i = i + 1
46     pass
47     return options
48    
49     def loadConfig(file):
50     """
51     returns a dictionary with keys of the form
52     <section>.<option> and the corresponding values
53     """
54     config={}
55     cp = ConfigParser.ConfigParser()
56     cp.read(file)
57     for sec in cp.sections():
58     # print 'Section',sec
59     for opt in cp.options(sec):
60     #print 'config['+sec+'.'+opt+'] = '+string.strip(cp.get(sec,opt))
61     config[sec+'.'+opt] = string.strip(cp.get(sec,opt))
62     return config
63    
64     ###########################################################################
65     def isInt(str):
66     """ Is the given string an integer ?"""
67     try: int(str)
68     except ValueError: return 0
69     return 1
70    
71     ###########################################################################
72     def isBool(str):
73     """ Is the given string 0 or 1 ?"""
74     if (str in ('0','1')): return 1
75     return 0
76    
77     ###########################################################################
78 nsmirnov 1.3 def parseRange(range):
79     """
80     Takes as the input a string with two integers separated by
81     the minus sign and returns the tuple with these numbers:
82     'n1-n2' -> (n1, n2)
83     'n1' -> (n1, n1)
84     """
85     start = None
86     end = None
87     minus = string.find(range, '-')
88     if ( minus < 0 ):
89     if isInt(range):
90     start = int(range)
91     end = start
92     pass
93     pass
94     else:
95     if isInt(range[:minus]) and isInt(range[minus+1:]):
96     start = int(range[:minus])
97     end = int(range[minus+1:])
98     pass
99     pass
100     return (start, end)
101    
102     ###########################################################################
103 nsmirnov 1.4 def parseRange2(range):
104     """
105     Takes as the input a string in the form of a comma-separated
106     numbers and ranges
107     and returns a list with all specified numbers:
108     'n1' -> [n1]
109     'n1-n2' -> [n1, n1+1, ..., n2]
110     'n1,n2-n3,n4' -> [n1, n2, n2+1, ..., n3, n4]
111     """
112 slacapra 1.30 result = []
113     if not range: return result
114 nsmirnov 1.4
115     comma = string.find(range, ',')
116     if comma == -1: left = range
117     else: left = range[:comma]
118    
119     (n1, n2) = parseRange(left)
120     while ( n1 <= n2 ):
121 slacapra 1.11 try:
122 slacapra 1.30 result.append(n1)
123 slacapra 1.11 n1 += 1
124     pass
125     except:
126     msg = 'Syntax error in range <'+range+'>'
127     raise CrabException(msg)
128 nsmirnov 1.4
129     if comma != -1:
130 slacapra 1.11 try:
131 slacapra 1.30 result.extend(parseRange2(range[comma+1:]))
132 slacapra 1.11 pass
133     except:
134     msg = 'Syntax error in range <'+range+'>'
135     raise CrabException(msg)
136 nsmirnov 1.4
137 slacapra 1.30 return result
138 nsmirnov 1.4
139     ###########################################################################
140 nsmirnov 1.3 def crabJobStatusToString(crab_status):
141     """
142     Convert one-letter crab job status into more readable string.
143     """
144 corvo 1.27 status={
145 slacapra 1.38 'C':'Created',
146     'D':'Done',
147 corvo 1.27 'H':'Hold',
148     'U':'Ready',
149     'I':'Scheduled',
150     'X':'Canceled',
151     'W':'Created',
152     'R':'Running',
153     'SC':'Checkpointed',
154     'SS':'Scheduled',
155     'SR':'Ready',
156     'RE':'Ready',
157     'SW':'Waiting',
158     'SU':'Submitted',
159     'S' :'Submitted (Boss)',
160     'UN':'Undefined',
161     'SK':'Cancelled',
162     'SD':'Done (Success)',
163     'SA':'Aborted',
164     'DA':'Done (Aborted)',
165     'SE':'Cleared',
166     'OR':'Done (Success)',
167     'A?':'Aborted',
168     'K':'Killed',
169     'E':'Cleared',
170     'Z':'Cleared (Corrupt)',
171     'NA':'Unknown',
172     'I?':'Idle',
173     'O?':'Done',
174     'R?':'Running'
175     }
176     # if crab_status == 'C': status = 'Created'
177     # elif crab_status == 'D': status = 'Done'
178     # elif crab_status == 'R': status = 'Submitted'#Should be running? ds
179     # elif crab_status == 'S': status = 'Submitted'
180     # elif crab_status == 'K': status = 'Killed'
181     # elif crab_status == 'X': status = 'None'
182     # elif crab_status == 'Y': status = 'Output retrieved'
183     # elif crab_status == 'A': status = 'Aborted'
184     # elif crab_status == 'RC': status = 'ReCreated'
185     # else: status = '???'
186     return status[crab_status]
187 nsmirnov 1.3
188     ###########################################################################
189 nsmirnov 1.1 def findLastWorkDir(dir_prefix, where = None):
190    
191     if not where: where = os.getcwd() + '/'
192     # dir_prefix usually has the form 'crab_0_'
193     pattern = re.compile(dir_prefix)
194    
195     file_list = []
196     for fl in os.listdir(where):
197     if pattern.match(fl):
198     file_list.append(fl)
199     pass
200     pass
201    
202     if len(file_list) == 0: return None
203    
204     file_list.sort()
205    
206     wdir = where + file_list[len(file_list)-1]
207     return wdir
208    
209     ###########################################################################
210     def importName(module_name, name):
211     """
212     Import a named object from a Python module,
213     i.e., it is an equivalent of 'from module_name import name'.
214     """
215     module = __import__(module_name, globals(), locals(), [name])
216     return vars(module)[name]
217    
218 spiga 1.9
219 slacapra 1.11 ###########################################################################
220 spiga 1.28
221 slacapra 1.29 ### WARNING This Function become USELESS after Boss API implementation
222 gutsche 1.24 def runBossCommand(cmd, printout=0, timeout=3600):
223 slacapra 1.11 """
224     Cd to correct directory before running a boss command
225     """
226     cwd = os.getcwd()
227     os.chdir(common.work_space.shareDir())
228     out = runCommand(cmd, printout, timeout)
229     os.chdir(cwd)
230     return out
231 spiga 1.9
232 nsmirnov 1.1 ###########################################################################
233 slacapra 1.16 def readable(fd):
234     return bool(select.select([fd], [], [], 0))
235    
236     ###########################################################################
237     def makeNonBlocking(fd):
238     fl = fcntl.fcntl(fd, fcntl.F_GETFL)
239     try:
240     fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NDELAY)
241     except AttributeError:
242     fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.FNDELAY)
243    
244     ###########################################################################
245 slacapra 1.11 def runCommand(cmd, printout=0, timeout=-1):
246 nsmirnov 1.1 """
247     Run command 'cmd'.
248     Returns command stdoutput+stderror string on success,
249     or None if an error occurred.
250 slacapra 1.16 Following recipe on http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52296
251 nsmirnov 1.1 """
252 fanzago 1.15
253 slacapra 1.11 if printout:
254     common.logger.message(cmd)
255     else:
256 slacapra 1.13 common.logger.debug(10,cmd)
257 slacapra 1.11 common.logger.write(cmd)
258 slacapra 1.29 pass
259 slacapra 1.11
260 slacapra 1.16 child = popen2.Popen3(cmd, 1) # capture stdout and stderr from command
261     child.tochild.close() # don't need to talk to child
262     outfile = child.fromchild
263     outfd = outfile.fileno()
264     errfile = child.childerr
265     errfd = errfile.fileno()
266     makeNonBlocking(outfd) # don't deadlock!
267     makeNonBlocking(errfd)
268     outdata = []
269     errdata = []
270     outeof = erreof = 0
271    
272     if timeout > 0 :
273     maxwaittime = time.time() + timeout
274    
275     err = -1
276     while (timeout == -1 or time.time() < maxwaittime):
277     ready = select.select([outfd,errfd],[],[]) # wait for input
278     if outfd in ready[0]:
279     outchunk = outfile.read()
280     if outchunk == '': outeof = 1
281     outdata.append(outchunk)
282     if errfd in ready[0]:
283     errchunk = errfile.read()
284     if errchunk == '': erreof = 1
285     errdata.append(errchunk)
286     if outeof and erreof:
287     err = child.wait()
288     break
289 slacapra 1.21 select.select([],[],[],.01) # give a little time for buffers to fill
290 slacapra 1.16 if err == -1:
291     # kill the pid
292 slacapra 1.18 common.logger.message('killing process '+(cmd)+' with timeout '+str(timeout))
293 slacapra 1.16 os.kill (child.pid, 9)
294 slacapra 1.11 err = child.wait()
295 slacapra 1.16
296 fanzago 1.17 cmd_out = string.join(outdata,"")
297     cmd_err = string.join(errdata,"")
298    
299 slacapra 1.11 if err:
300     common.logger.message('`'+cmd+'`\n failed with exit code '
301     +`err`+'='+`(err&0xff)`+'(signal)+'
302     +`(err>>8)`+'(status)')
303     common.logger.message(cmd_out)
304     common.logger.message(cmd_err)
305 nsmirnov 1.1 return None
306    
307 fanzago 1.17 # cmd_out = string.join(outdata,"")
308     # cmd_err = string.join(errdata,"")
309 nsmirnov 1.1 cmd_out = cmd_out + cmd_err
310 slacapra 1.11 if printout:
311     common.logger.message(cmd_out)
312     else:
313 slacapra 1.13 common.logger.debug(10,cmd_out)
314 slacapra 1.11 common.logger.write(cmd_out)
315 slacapra 1.29 pass
316 slacapra 1.16 #print "<"+cmd_out+">"
317 nsmirnov 1.1 return cmd_out
318 nsmirnov 1.4
319 slacapra 1.11 ####################################
320 gutsche 1.20 def makeCksum(filename) :
321     """
322     make chksum using filename and content of file
323     """
324    
325 slacapra 1.31 tobedeleted=0
326 slacapra 1.29 try:
327     import tempfile
328     tmpfile= tempfile.NamedTemporaryFile(mode='w')
329     tmp_filename = tmpfile.name
330     except:
331     ## SL in case py2.2 is used, fall back to old solution
332     tmp_filename = tempfile.mktemp()
333     tmpfile= open(tmp_filename,'w')
334     tobedeleted=1
335 gutsche 1.20
336     # add filename as first line
337 slacapra 1.29 tmpfile.write(filename+'\n')
338 gutsche 1.20
339     # fill input file in tmp file
340 slacapra 1.30 infile = open(filename)
341     tmpfile.writelines(infile.readlines())
342 slacapra 1.29 tmpfile.flush()
343 slacapra 1.30 infile.close()
344 gutsche 1.20
345     cmd = 'cksum '+tmp_filename
346     cmd_out = runCommand(cmd)
347    
348     cksum = cmd_out.split()[0]
349    
350 slacapra 1.29 ## SL this is not needed if we use NamedTemporaryFile, which is not available in py2.2
351     if (tobedeleted): os.remove(tmp_filename)
352 gutsche 1.20
353     return cksum
354    
355 gutsche 1.32 def spanRanges(jobArray):
356     """
357     take array of job numbers and concatenate 1,2,3 to 1-3
358     return string
359     """
360    
361     output = ""
362 mcinquil 1.35 jobArray.sort()
363    
364 gutsche 1.32 previous = jobArray[0]-1
365     for job in jobArray:
366     if previous+1 == job:
367     previous = job
368     if len(output) > 0 :
369     if output[-1] != "-":
370     output += "-"
371     else :
372     output += str(previous)
373     else:
374     output += str(previous) + "," + str(job)
375 mcinquil 1.35 #output += "," + str(job)
376 gutsche 1.32 previous = job
377     if len(jobArray) > 1 :
378     output += str(previous)
379    
380     return output
381    
382 gutsche 1.20 ####################################
383 nsmirnov 1.4 if __name__ == '__main__':
384     print 'sys.argv[1] =',sys.argv[1]
385     list = parseRange2(sys.argv[1])
386     print list
387 slacapra 1.29 cksum = makeCksum("crab_util.py")
388     print cksum
389 nsmirnov 1.4