1 |
spiga |
1.80 |
##########################################################################
|
2 |
nsmirnov |
1.1 |
#
|
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 |
spiga |
1.113 |
import string, sys, os, time, signal
|
8 |
spiga |
1.100 |
import ConfigParser, re, select, fcntl
|
9 |
ewv |
1.89 |
import statvfs
|
10 |
spiga |
1.100 |
from subprocess import Popen, PIPE, STDOUT
|
11 |
nsmirnov |
1.1 |
|
12 |
nsmirnov |
1.2 |
import common
|
13 |
slacapra |
1.30 |
from crab_exceptions import CrabException
|
14 |
spiga |
1.42 |
from ServerConfig import *
|
15 |
nsmirnov |
1.1 |
|
16 |
|
|
###########################################################################
|
17 |
|
|
def parseOptions(argv):
|
18 |
|
|
"""
|
19 |
|
|
Parses command-line options.
|
20 |
|
|
Returns a dictionary with specified options as keys:
|
21 |
|
|
-opt1 --> 'opt1' : None
|
22 |
|
|
-opt2 val --> 'opt2' : 'val'
|
23 |
|
|
-opt3=val --> 'opt3' : 'val'
|
24 |
|
|
Usually called as
|
25 |
|
|
options = parseOptions(sys.argv[1:])
|
26 |
|
|
"""
|
27 |
|
|
options = {}
|
28 |
|
|
argc = len(argv)
|
29 |
|
|
i = 0
|
30 |
|
|
while ( i < argc ):
|
31 |
|
|
if argv[i][0] != '-':
|
32 |
|
|
i = i + 1
|
33 |
|
|
continue
|
34 |
|
|
eq = string.find(argv[i], '=')
|
35 |
|
|
if eq > 0 :
|
36 |
|
|
opt = argv[i][:eq]
|
37 |
|
|
val = argv[i][eq+1:]
|
38 |
|
|
pass
|
39 |
|
|
else:
|
40 |
|
|
opt = argv[i]
|
41 |
|
|
val = None
|
42 |
|
|
if ( i+1 < argc and argv[i+1][0] != '-' ):
|
43 |
|
|
i = i + 1
|
44 |
|
|
val = argv[i]
|
45 |
|
|
pass
|
46 |
|
|
pass
|
47 |
|
|
options[opt] = val
|
48 |
|
|
i = i + 1
|
49 |
|
|
pass
|
50 |
|
|
return options
|
51 |
|
|
|
52 |
slacapra |
1.47 |
def loadConfig(file, config):
|
53 |
nsmirnov |
1.1 |
"""
|
54 |
|
|
returns a dictionary with keys of the form
|
55 |
|
|
<section>.<option> and the corresponding values
|
56 |
|
|
"""
|
57 |
slacapra |
1.47 |
#config={}
|
58 |
nsmirnov |
1.1 |
cp = ConfigParser.ConfigParser()
|
59 |
|
|
cp.read(file)
|
60 |
|
|
for sec in cp.sections():
|
61 |
|
|
for opt in cp.options(sec):
|
62 |
spiga |
1.79 |
## temporary check. Allow compatibility
|
63 |
ewv |
1.89 |
new_sec = sec
|
64 |
spiga |
1.79 |
if sec == 'EDG':
|
65 |
spiga |
1.80 |
print ('\tWARNING: The [EDG] section is now deprecated.\n\tPlease remove it and use [GRID] instead.\n')
|
66 |
ewv |
1.89 |
new_sec = 'GRID'
|
67 |
spiga |
1.79 |
config[new_sec+'.'+opt] = string.strip(cp.get(sec,opt))
|
68 |
nsmirnov |
1.1 |
return config
|
69 |
|
|
|
70 |
|
|
###########################################################################
|
71 |
|
|
def isInt(str):
|
72 |
|
|
""" Is the given string an integer ?"""
|
73 |
|
|
try: int(str)
|
74 |
|
|
except ValueError: return 0
|
75 |
|
|
return 1
|
76 |
|
|
|
77 |
|
|
###########################################################################
|
78 |
|
|
def isBool(str):
|
79 |
|
|
""" Is the given string 0 or 1 ?"""
|
80 |
|
|
if (str in ('0','1')): return 1
|
81 |
|
|
return 0
|
82 |
|
|
|
83 |
|
|
###########################################################################
|
84 |
nsmirnov |
1.3 |
def parseRange(range):
|
85 |
|
|
"""
|
86 |
|
|
Takes as the input a string with two integers separated by
|
87 |
|
|
the minus sign and returns the tuple with these numbers:
|
88 |
|
|
'n1-n2' -> (n1, n2)
|
89 |
|
|
'n1' -> (n1, n1)
|
90 |
|
|
"""
|
91 |
|
|
start = None
|
92 |
|
|
end = None
|
93 |
|
|
minus = string.find(range, '-')
|
94 |
|
|
if ( minus < 0 ):
|
95 |
|
|
if isInt(range):
|
96 |
|
|
start = int(range)
|
97 |
|
|
end = start
|
98 |
|
|
pass
|
99 |
|
|
pass
|
100 |
|
|
else:
|
101 |
|
|
if isInt(range[:minus]) and isInt(range[minus+1:]):
|
102 |
|
|
start = int(range[:minus])
|
103 |
|
|
end = int(range[minus+1:])
|
104 |
|
|
pass
|
105 |
|
|
pass
|
106 |
|
|
return (start, end)
|
107 |
|
|
|
108 |
|
|
###########################################################################
|
109 |
nsmirnov |
1.4 |
def parseRange2(range):
|
110 |
|
|
"""
|
111 |
|
|
Takes as the input a string in the form of a comma-separated
|
112 |
|
|
numbers and ranges
|
113 |
|
|
and returns a list with all specified numbers:
|
114 |
|
|
'n1' -> [n1]
|
115 |
|
|
'n1-n2' -> [n1, n1+1, ..., n2]
|
116 |
|
|
'n1,n2-n3,n4' -> [n1, n2, n2+1, ..., n3, n4]
|
117 |
|
|
"""
|
118 |
slacapra |
1.30 |
result = []
|
119 |
|
|
if not range: return result
|
120 |
nsmirnov |
1.4 |
|
121 |
|
|
comma = string.find(range, ',')
|
122 |
|
|
if comma == -1: left = range
|
123 |
|
|
else: left = range[:comma]
|
124 |
|
|
|
125 |
|
|
(n1, n2) = parseRange(left)
|
126 |
|
|
while ( n1 <= n2 ):
|
127 |
slacapra |
1.11 |
try:
|
128 |
slacapra |
1.30 |
result.append(n1)
|
129 |
slacapra |
1.11 |
n1 += 1
|
130 |
|
|
pass
|
131 |
|
|
except:
|
132 |
|
|
msg = 'Syntax error in range <'+range+'>'
|
133 |
|
|
raise CrabException(msg)
|
134 |
nsmirnov |
1.4 |
|
135 |
|
|
if comma != -1:
|
136 |
slacapra |
1.11 |
try:
|
137 |
slacapra |
1.30 |
result.extend(parseRange2(range[comma+1:]))
|
138 |
slacapra |
1.11 |
pass
|
139 |
|
|
except:
|
140 |
|
|
msg = 'Syntax error in range <'+range+'>'
|
141 |
|
|
raise CrabException(msg)
|
142 |
nsmirnov |
1.4 |
|
143 |
slacapra |
1.30 |
return result
|
144 |
nsmirnov |
1.4 |
|
145 |
|
|
###########################################################################
|
146 |
nsmirnov |
1.1 |
def findLastWorkDir(dir_prefix, where = None):
|
147 |
|
|
|
148 |
|
|
if not where: where = os.getcwd() + '/'
|
149 |
|
|
# dir_prefix usually has the form 'crab_0_'
|
150 |
|
|
pattern = re.compile(dir_prefix)
|
151 |
|
|
|
152 |
slacapra |
1.76 |
file_list = [f for f in os.listdir(where) if os.path.isdir(f) and pattern.match(f)]
|
153 |
nsmirnov |
1.1 |
|
154 |
|
|
if len(file_list) == 0: return None
|
155 |
|
|
|
156 |
|
|
file_list.sort()
|
157 |
|
|
|
158 |
slacapra |
1.76 |
wdir = where + file_list[-1]
|
159 |
nsmirnov |
1.1 |
return wdir
|
160 |
|
|
|
161 |
|
|
###########################################################################
|
162 |
mcinquil |
1.99 |
def checkCRABVersion(current, url = "http://cmsdoc.cern.ch/cms/LCG/crab/config/", fileName = "allowed_releases.conf"):
|
163 |
mcinquil |
1.98 |
"""
|
164 |
|
|
_checkCRABVersion_
|
165 |
|
|
|
166 |
|
|
compare current release with allowed releases
|
167 |
|
|
format of allowed release: ['2.6.5','2.6.6','2.7.*']
|
168 |
|
|
"""
|
169 |
spiga |
1.111 |
result=[]
|
170 |
mcinquil |
1.98 |
match_result = False
|
171 |
|
|
from Downloader import Downloader
|
172 |
spiga |
1.107 |
blacklist = Downloader(url)
|
173 |
spiga |
1.111 |
try:
|
174 |
|
|
result =eval(blacklist.config(fileName))
|
175 |
|
|
except:
|
176 |
|
|
common.logger.info("ERROR: Problem reading allowed releases file...")
|
177 |
mcinquil |
1.98 |
current_dot = current.split('.')
|
178 |
|
|
for version in result:
|
179 |
|
|
if version.find('.') != -1:
|
180 |
|
|
version_dot = version.split('.')
|
181 |
mcinquil |
1.116 |
temp = False
|
182 |
mcinquil |
1.98 |
for compare in map(None, current_dot, version_dot):
|
183 |
|
|
if compare[1].find('*') != -1:
|
184 |
|
|
return True
|
185 |
|
|
elif int(compare[0]) != int(compare[1]):
|
186 |
mcinquil |
1.116 |
temp = False
|
187 |
mcinquil |
1.98 |
break
|
188 |
mcinquil |
1.116 |
else:
|
189 |
|
|
temp = True
|
190 |
|
|
if temp:
|
191 |
|
|
return temp
|
192 |
mcinquil |
1.98 |
elif version == '*':
|
193 |
|
|
return True
|
194 |
|
|
return False
|
195 |
|
|
|
196 |
|
|
###########################################################################
|
197 |
mcinquil |
1.115 |
def getCentralConfigLink(linkname, url = "http://cmsdoc.cern.ch/cms/LCG/crab/config/", fileName = "URLs.conf"):
|
198 |
|
|
"""
|
199 |
|
|
_getCentralConfigLink_
|
200 |
|
|
|
201 |
|
|
This retrieves the remote URLs file containing a dictionary of a central manager URLs
|
202 |
|
|
{
|
203 |
|
|
'reportLogURL': 'http://gangamon.cern.ch/django/cmserrorreports/',
|
204 |
|
|
'dashbTaskMon': 'http://dashb-cms-job-task.cern.ch/taskmon.html#task=',
|
205 |
|
|
'servTaskMon' : 'http://glidein-mon.t2.ucsd.edu:8080/dashboard/ajaxproxy.jsp?p='
|
206 |
|
|
}
|
207 |
|
|
"""
|
208 |
|
|
result = {}
|
209 |
|
|
from Downloader import Downloader
|
210 |
|
|
links = Downloader(url)
|
211 |
|
|
try:
|
212 |
|
|
result = eval(links.config(fileName))
|
213 |
|
|
common.logger.debug(str(result))
|
214 |
|
|
except:
|
215 |
|
|
common.logger.info("ERROR: Problem reading URLs releases file...")
|
216 |
|
|
if result.has_key(linkname):
|
217 |
|
|
return result[linkname]
|
218 |
|
|
common.logger.info("ERROR: Problem reading URLs releases file: no %s present!" % linkname)
|
219 |
|
|
return ''
|
220 |
|
|
|
221 |
|
|
###########################################################################
|
222 |
nsmirnov |
1.1 |
def importName(module_name, name):
|
223 |
|
|
"""
|
224 |
|
|
Import a named object from a Python module,
|
225 |
|
|
i.e., it is an equivalent of 'from module_name import name'.
|
226 |
|
|
"""
|
227 |
|
|
module = __import__(module_name, globals(), locals(), [name])
|
228 |
|
|
return vars(module)[name]
|
229 |
|
|
|
230 |
|
|
###########################################################################
|
231 |
slacapra |
1.16 |
def readable(fd):
|
232 |
ewv |
1.44 |
return bool(select.select([fd], [], [], 0))
|
233 |
slacapra |
1.16 |
|
234 |
|
|
###########################################################################
|
235 |
|
|
def makeNonBlocking(fd):
|
236 |
|
|
fl = fcntl.fcntl(fd, fcntl.F_GETFL)
|
237 |
|
|
try:
|
238 |
|
|
fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NDELAY)
|
239 |
|
|
except AttributeError:
|
240 |
|
|
fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.FNDELAY)
|
241 |
|
|
|
242 |
|
|
###########################################################################
|
243 |
spiga |
1.100 |
def setPgid():
|
244 |
nsmirnov |
1.1 |
"""
|
245 |
spiga |
1.100 |
preexec_fn for Popen to set subprocess pgid
|
246 |
|
|
|
247 |
|
|
"""
|
248 |
|
|
|
249 |
|
|
os.setpgid( os.getpid(), 0 )
|
250 |
|
|
|
251 |
belforte |
1.119 |
def runCommand(command, printout=0, timeout=30.,errorCode=False):
|
252 |
spiga |
1.100 |
"""
|
253 |
|
|
_executeCommand_
|
254 |
|
|
|
255 |
|
|
Util it execute the command provided in a popen object with a timeout
|
256 |
nsmirnov |
1.1 |
"""
|
257 |
fanzago |
1.15 |
|
258 |
spiga |
1.100 |
start = time.time()
|
259 |
|
|
p = Popen( command, shell=True, \
|
260 |
|
|
stdin=PIPE, stdout=PIPE, stderr=STDOUT, \
|
261 |
|
|
close_fds=True, preexec_fn=setPgid )
|
262 |
|
|
|
263 |
|
|
# playing with fd
|
264 |
|
|
fd = p.stdout.fileno()
|
265 |
|
|
flags = fcntl.fcntl(fd, fcntl.F_GETFL)
|
266 |
|
|
fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)
|
267 |
|
|
|
268 |
|
|
# return values
|
269 |
|
|
timedOut = False
|
270 |
|
|
outc = []
|
271 |
|
|
|
272 |
|
|
while 1:
|
273 |
|
|
(r, w, e) = select.select([fd], [], [], timeout)
|
274 |
|
|
|
275 |
|
|
if fd not in r :
|
276 |
|
|
timedOut = True
|
277 |
|
|
break
|
278 |
slacapra |
1.11 |
|
279 |
spiga |
1.100 |
read = p.stdout.read()
|
280 |
|
|
if read != '' :
|
281 |
|
|
outc.append( read )
|
282 |
|
|
else :
|
283 |
slacapra |
1.16 |
break
|
284 |
spiga |
1.100 |
|
285 |
|
|
if timedOut :
|
286 |
belforte |
1.119 |
common.logger.info('Command %s timed out after %d sec' % (command, int(timeout)))
|
287 |
spiga |
1.100 |
stop = time.time()
|
288 |
|
|
try:
|
289 |
|
|
os.killpg( os.getpgid(p.pid), signal.SIGTERM)
|
290 |
|
|
os.kill( p.pid, signal.SIGKILL)
|
291 |
|
|
p.wait()
|
292 |
|
|
p.stdout.close()
|
293 |
|
|
except OSError, err :
|
294 |
spiga |
1.101 |
common.logger.info(
|
295 |
spiga |
1.100 |
'Warning: an error occurred killing subprocess [%s]' \
|
296 |
|
|
% str(err) )
|
297 |
|
|
|
298 |
belforte |
1.119 |
raise CrabException("Timeout")
|
299 |
spiga |
1.100 |
|
300 |
|
|
try:
|
301 |
|
|
p.wait()
|
302 |
|
|
p.stdout.close()
|
303 |
|
|
except OSError, err:
|
304 |
spiga |
1.101 |
common.logger.info( 'Warning: an error occurred closing subprocess [%s] %s %s' \
|
305 |
spiga |
1.100 |
% (str(err), ''.join(outc), p.returncode ))
|
306 |
|
|
|
307 |
|
|
returncode = p.returncode
|
308 |
|
|
if returncode != 0 :
|
309 |
|
|
msg = 'Command: %s \n failed with exit code %s \n'%(command,returncode)
|
310 |
edelmann |
1.105 |
msg += str(''.join(outc))
|
311 |
spiga |
1.109 |
if not errorCode:
|
312 |
|
|
common.logger.info( msg )
|
313 |
|
|
return None
|
314 |
|
|
if errorCode:
|
315 |
|
|
if returncode is None :returncode=-66666
|
316 |
|
|
return returncode,''.join(outc)
|
317 |
belforte |
1.119 |
|
318 |
spiga |
1.100 |
return ''.join(outc)
|
319 |
|
|
|
320 |
nsmirnov |
1.4 |
|
321 |
slacapra |
1.11 |
####################################
|
322 |
gutsche |
1.20 |
def makeCksum(filename) :
|
323 |
|
|
"""
|
324 |
ewv |
1.44 |
make check sum using filename and content of file
|
325 |
gutsche |
1.20 |
"""
|
326 |
|
|
|
327 |
ewv |
1.44 |
from zlib import crc32
|
328 |
|
|
hashString = filename
|
329 |
gutsche |
1.20 |
|
330 |
ewv |
1.44 |
inFile = open(filename, 'r')
|
331 |
|
|
hashString += inFile.read()
|
332 |
|
|
inFile.close()
|
333 |
gutsche |
1.20 |
|
334 |
ewv |
1.44 |
cksum = str(crc32(hashString))
|
335 |
gutsche |
1.20 |
return cksum
|
336 |
|
|
|
337 |
ewv |
1.52 |
|
338 |
gutsche |
1.32 |
def spanRanges(jobArray):
|
339 |
|
|
"""
|
340 |
|
|
take array of job numbers and concatenate 1,2,3 to 1-3
|
341 |
|
|
return string
|
342 |
|
|
"""
|
343 |
|
|
|
344 |
|
|
output = ""
|
345 |
mcinquil |
1.35 |
jobArray.sort()
|
346 |
ewv |
1.44 |
|
347 |
gutsche |
1.32 |
previous = jobArray[0]-1
|
348 |
|
|
for job in jobArray:
|
349 |
|
|
if previous+1 == job:
|
350 |
|
|
previous = job
|
351 |
|
|
if len(output) > 0 :
|
352 |
|
|
if output[-1] != "-":
|
353 |
|
|
output += "-"
|
354 |
|
|
else :
|
355 |
|
|
output += str(previous)
|
356 |
|
|
else:
|
357 |
|
|
output += str(previous) + "," + str(job)
|
358 |
mcinquil |
1.35 |
#output += "," + str(job)
|
359 |
gutsche |
1.32 |
previous = job
|
360 |
|
|
if len(jobArray) > 1 :
|
361 |
|
|
output += str(previous)
|
362 |
|
|
|
363 |
|
|
return output
|
364 |
|
|
|
365 |
spiga |
1.40 |
def displayReport(self, header, lines, xml=''):
|
366 |
ewv |
1.44 |
|
367 |
belforte |
1.117 |
horizontalRuler=''
|
368 |
|
|
for i in range(80):
|
369 |
|
|
horizontalRuler+='-'
|
370 |
|
|
horizontalRuler+='\n'
|
371 |
spiga |
1.49 |
counter = 0
|
372 |
|
|
printline = ''
|
373 |
|
|
printline+= header
|
374 |
spiga |
1.87 |
msg = '\n%s'%printline
|
375 |
spiga |
1.49 |
|
376 |
|
|
for i in range(len(lines)):
|
377 |
|
|
if counter != 0 and counter%10 == 0 :
|
378 |
belforte |
1.117 |
msg += horizontalRuler
|
379 |
spiga |
1.82 |
msg+= '%s\n'%lines[i]
|
380 |
spiga |
1.49 |
counter += 1
|
381 |
|
|
if xml != '' :
|
382 |
spiga |
1.40 |
fileName = common.work_space.shareDir() + xml
|
383 |
|
|
task = common._db.getTask()
|
384 |
|
|
taskXML = common._db.serializeTask(task)
|
385 |
spiga |
1.87 |
common.logger.log(10-1, taskXML)
|
386 |
spiga |
1.40 |
f = open(fileName, 'w')
|
387 |
|
|
f.write(taskXML)
|
388 |
|
|
f.close()
|
389 |
|
|
pass
|
390 |
spiga |
1.82 |
common.logger.info(msg)
|
391 |
spiga |
1.39 |
|
392 |
spiga |
1.42 |
def CliServerParams(self):
|
393 |
slacapra |
1.45 |
"""
|
394 |
|
|
Init client-server interactions
|
395 |
|
|
"""
|
396 |
|
|
self.srvCfg = {}
|
397 |
slacapra |
1.63 |
## First I have to check if the decision has been already taken...
|
398 |
|
|
task = common._db.getTask()
|
399 |
slacapra |
1.81 |
if task['serverName']!=None and task['serverName']!="":
|
400 |
slacapra |
1.63 |
self.cfg_params['CRAB.server_name']=task['serverName']
|
401 |
slacapra |
1.81 |
|
402 |
|
|
if self.cfg_params.has_key('CRAB.server_name'):
|
403 |
|
|
self.srvCfg = ServerConfig(self.cfg_params['CRAB.server_name']).config()
|
404 |
|
|
elif self.cfg_params.has_key('CRAB.use_server'):
|
405 |
slacapra |
1.77 |
serverName=self.cfg_params.get('CRAB.server_name','default')
|
406 |
slacapra |
1.62 |
if self.cfg_params.has_key('CRAB.server_name'):
|
407 |
|
|
serverName=self.cfg_params['CRAB.server_name']
|
408 |
|
|
else:
|
409 |
|
|
serverName='default'
|
410 |
|
|
self.srvCfg = ServerConfig(serverName).config()
|
411 |
slacapra |
1.61 |
else:
|
412 |
|
|
msg = 'No server selected or port specified.\n'
|
413 |
|
|
msg += 'Please specify a server in the crab cfg file'
|
414 |
|
|
raise CrabException(msg)
|
415 |
|
|
return
|
416 |
slacapra |
1.81 |
# save the serverName for future use
|
417 |
|
|
opsToBeSaved={}
|
418 |
|
|
opsToBeSaved['serverName']=self.srvCfg['serverGenericName']
|
419 |
|
|
common._db.updateTask_(opsToBeSaved)
|
420 |
slacapra |
1.45 |
|
421 |
slacapra |
1.61 |
self.server_admin = str(self.srvCfg['serverAdmin'])
|
422 |
|
|
self.server_dn = str(self.srvCfg['serverDN'])
|
423 |
spiga |
1.58 |
|
424 |
slacapra |
1.61 |
self.server_name = str(self.srvCfg['serverName'])
|
425 |
|
|
self.server_port = int(self.srvCfg['serverPort'])
|
426 |
slacapra |
1.45 |
|
427 |
slacapra |
1.61 |
self.storage_name = str(self.srvCfg['storageName'])
|
428 |
|
|
self.storage_path = str(self.srvCfg['storagePath'])
|
429 |
mcinquil |
1.97 |
|
430 |
riahi |
1.114 |
if self.srvCfg.has_key('proxyPath'):
|
431 |
|
|
self.proxy_path = str(self.srvCfg['proxyPath'])
|
432 |
|
|
else:
|
433 |
|
|
self.proxy_path = os.path.dirname(str(self.srvCfg['storagePath'])) + '/proxyCache'
|
434 |
|
|
|
435 |
slacapra |
1.61 |
self.storage_proto = str(self.srvCfg['storageProtocol'])
|
436 |
mcinquil |
1.97 |
if self.cfg_params.has_key('USER.client'):
|
437 |
|
|
self.storage_proto = self.cfg_params['USER.client'].lower()
|
438 |
|
|
|
439 |
slacapra |
1.61 |
self.storage_port = str(self.srvCfg['storagePort'])
|
440 |
spiga |
1.39 |
|
441 |
ewv |
1.44 |
def bulkControl(self,list):
|
442 |
slacapra |
1.45 |
"""
|
443 |
|
|
Check the BULK size and reduce collection ...if needed
|
444 |
|
|
"""
|
445 |
|
|
max_size = 400
|
446 |
|
|
sub_bulk = []
|
447 |
|
|
if len(list) > int(max_size):
|
448 |
|
|
n_sub_bulk = int( int(len(list) ) / int(max_size) )
|
449 |
mcinquil |
1.53 |
for n in xrange(n_sub_bulk):
|
450 |
slacapra |
1.45 |
first =n*int(max_size)
|
451 |
|
|
last = (n+1)*int(max_size)
|
452 |
|
|
sub_bulk.append(list[first:last])
|
453 |
belforte |
1.118 |
if len(list[last:]) < 50:
|
454 |
|
|
for pp in list[last:]:
|
455 |
slacapra |
1.45 |
sub_bulk[n_sub_bulk-1].append(pp)
|
456 |
spiga |
1.43 |
else:
|
457 |
mcinquil |
1.53 |
sub_bulk.append(list[last:])
|
458 |
slacapra |
1.45 |
else:
|
459 |
|
|
sub_bulk.append(list)
|
460 |
|
|
|
461 |
|
|
return sub_bulk
|
462 |
ewv |
1.89 |
|
463 |
slacapra |
1.45 |
|
464 |
spiga |
1.69 |
def getUserName():
|
465 |
spiga |
1.66 |
"""
|
466 |
|
|
extract user name from either SiteDB or Unix
|
467 |
|
|
"""
|
468 |
mcinquil |
1.96 |
if common.scheduler.name().upper() in ['LSF', 'CAF', 'SGE', 'PBS']:
|
469 |
ewv |
1.89 |
common.logger.log(10-1, "Using as username the Unix user name")
|
470 |
|
|
userName = unixUserName()
|
471 |
spiga |
1.66 |
else :
|
472 |
ewv |
1.89 |
userName = gethnUserNameFromSiteDB()
|
473 |
|
|
|
474 |
|
|
return userName
|
475 |
spiga |
1.66 |
|
476 |
spiga |
1.58 |
|
477 |
ewv |
1.89 |
def unixUserName():
|
478 |
spiga |
1.58 |
"""
|
479 |
|
|
extract username from whoami
|
480 |
|
|
"""
|
481 |
|
|
try:
|
482 |
ewv |
1.89 |
userName = runCommand("whoami")
|
483 |
|
|
userName = string.strip(userName)
|
484 |
spiga |
1.58 |
except:
|
485 |
|
|
msg = "Error. Problem with whoami command"
|
486 |
|
|
raise CrabException(msg)
|
487 |
ewv |
1.89 |
return userName
|
488 |
|
|
|
489 |
spiga |
1.66 |
|
490 |
spiga |
1.69 |
def getDN():
|
491 |
spiga |
1.66 |
"""
|
492 |
|
|
extract DN from user proxy's identity
|
493 |
|
|
"""
|
494 |
|
|
try:
|
495 |
|
|
userdn = runCommand("voms-proxy-info -identity")
|
496 |
|
|
userdn = string.strip(userdn)
|
497 |
farinafa |
1.112 |
#remove /CN=proxy that could cause problems with siteDB check at server-side
|
498 |
|
|
userdn = userdn.replace('/CN=proxy','')
|
499 |
spiga |
1.66 |
#search for a / to avoid picking up warning messages
|
500 |
|
|
userdn = userdn[userdn.find('/'):]
|
501 |
|
|
except:
|
502 |
|
|
msg = "Error. Problem with voms-proxy-info -identity command"
|
503 |
|
|
raise CrabException(msg)
|
504 |
|
|
return userdn.split('\n')[0]
|
505 |
|
|
|
506 |
ewv |
1.89 |
|
507 |
spiga |
1.69 |
def gethnUserNameFromSiteDB():
|
508 |
spiga |
1.66 |
"""
|
509 |
|
|
extract user name from SiteDB
|
510 |
|
|
"""
|
511 |
|
|
from WMCore.Services.SiteDB.SiteDB import SiteDBJSON
|
512 |
|
|
hnUserName = None
|
513 |
spiga |
1.69 |
userdn = getDN()
|
514 |
ewv |
1.89 |
params = { 'cacheduration' : 24,
|
515 |
|
|
'logger' : common.logger() }
|
516 |
|
|
mySiteDB = SiteDBJSON(params)
|
517 |
ewv |
1.90 |
msg_ = "there is no user name associated to DN %s in SiteDB.\n" % userdn
|
518 |
|
|
msg_ += "You need to register in SiteDB with the instructions at https://twiki.cern.ch/twiki/bin/view/CMS/SiteDBForCRAB"
|
519 |
spiga |
1.66 |
try:
|
520 |
|
|
hnUserName = mySiteDB.dnUserName(dn=userdn)
|
521 |
ewv |
1.89 |
except Exception, text:
|
522 |
|
|
msg = "Error extracting user name from SiteDB: %s\n" % text
|
523 |
|
|
msg += " Check that you are registered in SiteDB, see https://twiki.cern.ch/twiki/bin/view/CMS/SiteDBForCRAB\n"
|
524 |
|
|
msg += ' or %s' % msg_
|
525 |
spiga |
1.66 |
raise CrabException(msg)
|
526 |
|
|
if not hnUserName:
|
527 |
ewv |
1.89 |
msg = "Error. %s" % msg_
|
528 |
spiga |
1.66 |
raise CrabException(msg)
|
529 |
|
|
return hnUserName
|
530 |
|
|
|
531 |
|
|
|
532 |
slacapra |
1.45 |
def numberFile(file, txt):
|
533 |
|
|
"""
|
534 |
|
|
append _'txt' before last extension of a file
|
535 |
|
|
"""
|
536 |
|
|
txt=str(txt)
|
537 |
|
|
p = string.split(file,".")
|
538 |
|
|
# take away last extension
|
539 |
|
|
name = p[0]
|
540 |
|
|
for x in p[1:-1]:
|
541 |
|
|
name=name+"."+x
|
542 |
|
|
# add "_txt"
|
543 |
|
|
if len(p)>1:
|
544 |
|
|
ext = p[len(p)-1]
|
545 |
|
|
result = name + '_' + txt + "." + ext
|
546 |
|
|
else:
|
547 |
|
|
result = name + '_' + txt
|
548 |
spiga |
1.43 |
|
549 |
slacapra |
1.45 |
return result
|
550 |
spiga |
1.46 |
|
551 |
|
|
def readTXTfile(self,inFileName):
|
552 |
|
|
"""
|
553 |
|
|
read file and return a list with the content
|
554 |
|
|
"""
|
555 |
|
|
out_list=[]
|
556 |
|
|
if os.path.exists(inFileName):
|
557 |
|
|
f = open(inFileName, 'r')
|
558 |
|
|
for line in f.readlines():
|
559 |
ewv |
1.52 |
out_list.append(string.strip(line))
|
560 |
spiga |
1.46 |
f.close()
|
561 |
|
|
else:
|
562 |
|
|
msg = ' file '+str(inFileName)+' not found.'
|
563 |
ewv |
1.52 |
raise CrabException(msg)
|
564 |
spiga |
1.46 |
return out_list
|
565 |
|
|
|
566 |
|
|
def writeTXTfile(self, outFileName, args):
|
567 |
|
|
"""
|
568 |
|
|
write a file with the given content ( args )
|
569 |
|
|
"""
|
570 |
|
|
outFile = open(outFileName,"a")
|
571 |
|
|
outFile.write(str(args))
|
572 |
|
|
outFile.close()
|
573 |
|
|
return
|
574 |
|
|
|
575 |
spiga |
1.54 |
def readableList(self,rawList):
|
576 |
ewv |
1.64 |
"""
|
577 |
|
|
Turn a list of numbers into a string like 1-5,7,9,12-20
|
578 |
|
|
"""
|
579 |
|
|
if not rawList:
|
580 |
|
|
return ''
|
581 |
|
|
|
582 |
slacapra |
1.56 |
listString = str(rawList[0])
|
583 |
|
|
endRange = ''
|
584 |
|
|
for i in range(1,len(rawList)):
|
585 |
|
|
if rawList[i] == rawList[i-1]+1:
|
586 |
|
|
endRange = str(rawList[i])
|
587 |
|
|
else:
|
588 |
|
|
if endRange:
|
589 |
|
|
listString += '-' + endRange + ',' + str(rawList[i])
|
590 |
|
|
endRange = ''
|
591 |
|
|
else:
|
592 |
|
|
listString += ',' + str(rawList[i])
|
593 |
|
|
if endRange:
|
594 |
|
|
listString += '-' + endRange
|
595 |
|
|
endRange = ''
|
596 |
ewv |
1.64 |
|
597 |
slacapra |
1.56 |
return listString
|
598 |
spiga |
1.54 |
|
599 |
spiga |
1.51 |
def getLocalDomain(self):
|
600 |
ewv |
1.52 |
"""
|
601 |
slacapra |
1.56 |
Get local domain name
|
602 |
ewv |
1.52 |
"""
|
603 |
spiga |
1.51 |
import socket
|
604 |
slacapra |
1.88 |
tmp=socket.getfqdn()
|
605 |
spiga |
1.51 |
dot=string.find(tmp,'.')
|
606 |
|
|
if (dot==-1):
|
607 |
|
|
msg='Unkown domain name. Cannot use local scheduler'
|
608 |
|
|
raise CrabException(msg)
|
609 |
|
|
localDomainName = string.split(tmp,'.',1)[-1]
|
610 |
ewv |
1.52 |
return localDomainName
|
611 |
spiga |
1.51 |
|
612 |
slacapra |
1.56 |
#######################################################
|
613 |
|
|
# Brian Bockelman bbockelm@cse.unl.edu
|
614 |
|
|
# Module to check the avaialble disk space on a specified directory.
|
615 |
|
|
#
|
616 |
|
|
|
617 |
|
|
def has_freespace(dir_name, needed_space_kilobytes):
|
618 |
belforte |
1.119 |
|
619 |
slacapra |
1.56 |
enough_unix_quota = False
|
620 |
|
|
enough_quota = False
|
621 |
|
|
enough_partition = False
|
622 |
|
|
enough_mount = False
|
623 |
|
|
try:
|
624 |
spiga |
1.109 |
enough_mount = check_mount(dir_name, needed_space_kilobytes)
|
625 |
|
|
except Exception,e :
|
626 |
belforte |
1.122 |
common.logger.debug(str(e)+" while checking mount. Treat as check OK")
|
627 |
spiga |
1.109 |
common.logger.log(10-1,e)
|
628 |
slacapra |
1.56 |
enough_mount = True
|
629 |
|
|
try:
|
630 |
|
|
enough_quota = check_quota(dir_name, needed_space_kilobytes)
|
631 |
spiga |
1.109 |
except Exception, e:
|
632 |
belforte |
1.122 |
common.logger.debug(str(e)+" while checking AFS quota. Treat as check OK")
|
633 |
spiga |
1.109 |
common.logger.log(10-1,e)
|
634 |
slacapra |
1.56 |
enough_quota = True
|
635 |
|
|
try:
|
636 |
|
|
enough_partition = check_partition(dir_name,
|
637 |
|
|
needed_space_kilobytes)
|
638 |
spiga |
1.109 |
except Exception, e:
|
639 |
belforte |
1.122 |
common.logger.debug(str(e)+" while checking partition. Treat as check OK")
|
640 |
spiga |
1.109 |
common.logger.log(10-1,e)
|
641 |
slacapra |
1.56 |
enough_partition = True
|
642 |
|
|
try:
|
643 |
|
|
enough_unix_quota = check_unix_quota(dir_name,
|
644 |
|
|
needed_space_kilobytes)
|
645 |
spiga |
1.109 |
except Exception, e:
|
646 |
belforte |
1.122 |
common.logger.debug(str(e)+" while checking unix_quota. Treat as check OK")
|
647 |
spiga |
1.109 |
common.logger.log(10-1,e)
|
648 |
slacapra |
1.56 |
enough_unix_quota = True
|
649 |
belforte |
1.119 |
|
650 |
slacapra |
1.56 |
return enough_mount and enough_quota and enough_partition \
|
651 |
|
|
and enough_unix_quota
|
652 |
|
|
|
653 |
|
|
def check_mount(dir_name, needed_space_kilobytes):
|
654 |
|
|
try:
|
655 |
|
|
vfs = os.statvfs(dir_name)
|
656 |
|
|
except:
|
657 |
|
|
raise Exception("Unable to query VFS for %s." % dir_name)
|
658 |
|
|
dev_free = vfs[statvfs.F_FRSIZE] * vfs[statvfs.F_BAVAIL]
|
659 |
|
|
return dev_free/1024 > needed_space_kilobytes
|
660 |
|
|
|
661 |
|
|
def check_quota(dir_name, needed_space_kilobytes):
|
662 |
spiga |
1.109 |
err,results = runCommand("/usr/bin/fs lq %s" % dir_name,errorCode=True)
|
663 |
|
|
if results and err == 0 :
|
664 |
|
|
try:
|
665 |
|
|
results = results.split('\n')[1].split()
|
666 |
|
|
quota, used = results[1:3]
|
667 |
|
|
avail = int(quota) - int(used)
|
668 |
|
|
return avail > needed_space_kilobytes
|
669 |
|
|
except:
|
670 |
|
|
raise Exception("Unable to parse AFS output.")
|
671 |
|
|
elif results and err !=0:
|
672 |
|
|
raise Exception(results)
|
673 |
slacapra |
1.56 |
|
674 |
|
|
def check_partition(dir_name, needed_space_kilobytes):
|
675 |
spiga |
1.109 |
err,results = runCommand("/usr/bin/fs diskfree %s" % dir_name,errorCode=True)
|
676 |
|
|
if results and err==0:
|
677 |
|
|
try:
|
678 |
|
|
results = results.split('\n')[1].split()
|
679 |
|
|
avail = results[3]
|
680 |
|
|
return int(avail) > needed_space_kilobytes
|
681 |
|
|
except:
|
682 |
|
|
raise Exception("Unable to parse AFS output.")
|
683 |
|
|
elif results and err !=0:
|
684 |
|
|
raise Exception(results)
|
685 |
slacapra |
1.56 |
|
686 |
|
|
def check_unix_quota(dir_name, needed_space_kilobytes):
|
687 |
spiga |
1.109 |
err0, results0 = runCommand("df %s" % dir_name,errorCode=True)
|
688 |
|
|
if results0 and err0==0:
|
689 |
|
|
fs = results0.split('\n')[1].split()[0]
|
690 |
belforte |
1.120 |
err,results = runCommand("quota -Q -u -g",errorCode=True)
|
691 |
spiga |
1.109 |
if err != 0:
|
692 |
|
|
raise Exception(results)
|
693 |
|
|
has_info = False
|
694 |
|
|
for line in results.splitlines():
|
695 |
|
|
info = line.split()
|
696 |
|
|
if info[0] in ['Filesystem', 'Disk']:
|
697 |
|
|
continue
|
698 |
|
|
if len(info) == 1:
|
699 |
|
|
filesystem = info[0]
|
700 |
|
|
has_info = False
|
701 |
|
|
if len(info) == 6:
|
702 |
|
|
used, limit = info[0], max(info[1], info[2])
|
703 |
|
|
has_info = True
|
704 |
|
|
if len(info) == 7:
|
705 |
|
|
filesystem, used, limit = info[0], info[1], max(info[2], info[3])
|
706 |
|
|
has_info = True
|
707 |
|
|
if has_info:
|
708 |
|
|
if filesystem != fs:
|
709 |
|
|
continue
|
710 |
|
|
avail = int(limit) - int(used)
|
711 |
|
|
if avail < needed_space_kilobytes:
|
712 |
|
|
return False
|
713 |
|
|
elif results0 and err0 !=0:
|
714 |
|
|
raise Exception(results0)
|
715 |
slacapra |
1.56 |
return True
|
716 |
spiga |
1.54 |
|
717 |
slacapra |
1.57 |
def getGZSize(gzipfile):
|
718 |
|
|
# return the uncompressed size of a gzipped file
|
719 |
|
|
import struct
|
720 |
|
|
f = open(gzipfile, "rb")
|
721 |
|
|
if f.read(2) != "\x1f\x8b":
|
722 |
|
|
raise IOError("not a gzip file")
|
723 |
|
|
f.seek(-4, 2)
|
724 |
ewv |
1.64 |
return struct.unpack("<i", f.read())[0]
|
725 |
slacapra |
1.57 |
|
726 |
spiga |
1.60 |
def showWebMon(server_name):
|
727 |
spiga |
1.72 |
taskName = common._db.queryTask('name')
|
728 |
spiga |
1.60 |
msg = ''
|
729 |
spiga |
1.71 |
msg +='You can also follow the status of this task on :\n'
|
730 |
spiga |
1.72 |
msg +='\tCMS Dashboard: http://dashb-cms-job-task.cern.ch/taskmon.html#task=%s\n'%(taskName)
|
731 |
ewv |
1.64 |
if server_name != '' :
|
732 |
spiga |
1.71 |
msg += '\tServer page: http://%s:8888/logginfo\n'%server_name
|
733 |
spiga |
1.72 |
msg += '\tYour task name is: %s \n'%taskName
|
734 |
spiga |
1.60 |
return msg
|
735 |
|
|
|
736 |
slacapra |
1.86 |
def SE2CMS(dests):
|
737 |
slacapra |
1.85 |
"""
|
738 |
|
|
Trasnsform a list of SE grid name into a list SE according to CMS naming convention
|
739 |
|
|
input: array of SE grid names
|
740 |
|
|
output: array of SE CMS names
|
741 |
|
|
"""
|
742 |
|
|
from ProdCommon.SiteDB.CmsSiteMapper import SECmsMap
|
743 |
|
|
se_cms = SECmsMap()
|
744 |
|
|
SEDestination = [se_cms[d] for d in dests]
|
745 |
|
|
return SEDestination
|
746 |
spiga |
1.60 |
|
747 |
slacapra |
1.86 |
def CE2CMS(dests):
|
748 |
|
|
"""
|
749 |
|
|
Trasnsform a list of CE grid name into a list SE according to CMS naming convention
|
750 |
|
|
input: array of CE grid names
|
751 |
|
|
output: array of CE CMS names
|
752 |
|
|
"""
|
753 |
|
|
from ProdCommon.SiteDB.CmsSiteMapper import CECmsMap
|
754 |
|
|
ce_cms = CECmsMap()
|
755 |
|
|
CEDestination = [ce_cms[d] for d in dests]
|
756 |
|
|
return CEDestination
|
757 |
|
|
|
758 |
spiga |
1.95 |
def checkLcgUtils( ):
|
759 |
mcinquil |
1.94 |
"""
|
760 |
|
|
_checkLcgUtils_
|
761 |
|
|
check the lcg-utils version and report
|
762 |
|
|
"""
|
763 |
|
|
import commands
|
764 |
|
|
cmd = "lcg-cp --version | grep lcg_util"
|
765 |
|
|
status, output = commands.getstatusoutput( cmd )
|
766 |
|
|
num_ver = -1
|
767 |
|
|
if output.find("not found") == -1 or status == 0:
|
768 |
|
|
temp = output.split("-")
|
769 |
|
|
version = ""
|
770 |
|
|
if len(temp) >= 2:
|
771 |
|
|
version = output.split("-")[1]
|
772 |
|
|
temp = version.split(".")
|
773 |
|
|
if len(temp) >= 1:
|
774 |
|
|
num_ver = int(temp[0])*10
|
775 |
|
|
num_ver += int(temp[1])
|
776 |
|
|
return num_ver
|
777 |
|
|
|
778 |
spiga |
1.95 |
def setLcgTimeout( ):
|
779 |
|
|
"""
|
780 |
|
|
"""
|
781 |
|
|
opt = ' -t 600 '
|
782 |
|
|
if checkLcgUtils() >= 17: opt=' --connect-timeout 600 '
|
783 |
|
|
return opt
|
784 |
|
|
|
785 |
spiga |
1.110 |
def schedulerGlite():
|
786 |
|
|
|
787 |
|
|
scheduler = None
|
788 |
|
|
err, out = runCommand('glite-version',errorCode=True)
|
789 |
|
|
if err==0:
|
790 |
|
|
if out.strip().startswith('3.1'):
|
791 |
|
|
scheduler = 'SchedulerGLiteAPI'
|
792 |
|
|
else:
|
793 |
|
|
scheduler = 'SchedulerGLite'
|
794 |
|
|
else:
|
795 |
|
|
common.logger.info("error detecting glite version ")
|
796 |
|
|
|
797 |
|
|
return scheduler
|
798 |
spiga |
1.101 |
|
799 |
gutsche |
1.20 |
####################################
|
800 |
nsmirnov |
1.4 |
if __name__ == '__main__':
|
801 |
|
|
print 'sys.argv[1] =',sys.argv[1]
|
802 |
|
|
list = parseRange2(sys.argv[1])
|
803 |
|
|
print list
|
804 |
slacapra |
1.29 |
cksum = makeCksum("crab_util.py")
|
805 |
|
|
print cksum
|
806 |
ewv |
1.44 |
|