]>
Commit | Line | Data |
---|---|---|
6192bc61 | 1 | #!/usr/bin/env bash |
3fc2dd01 | 2 | #library of useful PWGPP related bash functions |
3 | #it REQUIRES BASH 4 !!!! | |
4 | #blame: Mikolaj Krzewicki, mkrzewic@cern.ch | |
5 | ||
6 | if [ ${BASH_VERSINFO} -lt 4 ]; then | |
7 | echo "bash version >= 4 needed, you have ${BASH_VERSION}, exiting..." | |
8 | exit 1 | |
9 | fi | |
10 | ||
11 | PWGPP_runMap=" | |
12 | 2010 108350 139517 | |
13 | 2011 140441 170593 | |
14 | 2012 171590 193766 | |
07566ff3 | 15 | 2013 194308 199146 |
16 | 2014 202369 206695 | |
17 | 2015 999999 999999 | |
18 | 2016 999999 999999 | |
3fc2dd01 | 19 | " |
20 | ||
21 | parseConfig() | |
22 | { | |
78eed544 | 23 | #parse command line arguments, they have to be in the form |
24 | # option=value | |
25 | #they are then set in the environment | |
26 | # | |
27 | #optionally a config file can be specified in the arguments: | |
28 | # configFile=<someFile> | |
29 | #config file sets variables: option=value | |
30 | #command line options override config file | |
3fc2dd01 | 31 | # |
32 | #recommended way of using (at the beginning of your funcion/script): | |
33 | # if ! parseConfig "${@}"; then return; fi | |
34 | ||
78eed544 | 35 | local args=("$@") |
3fc2dd01 | 36 | local opt="" |
37 | ||
38 | #first check if we will need to decode spaces | |
39 | local encodedSpaces="" | |
40 | for opt in "${args[@]}"; do | |
41 | [[ "${opt}" =~ encodedSpaces=.* ]] \ | |
42 | && encodedSpaces=1 \ | |
43 | && break | |
44 | done | |
45 | ||
46 | #then look for a configFile (if any) | |
47 | for opt in "${args[@]}"; do | |
48 | if [[ ${opt} =~ configFile=.* ]]; then | |
49 | eval "${opt}" | |
50 | [[ ! -f ${configFile} ]] \ | |
51 | && echo "configFile ${configFile} not found, exiting..." \ | |
52 | && return 1 | |
53 | echo "using config file: ${configFile}" | |
54 | source "${configFile}" | |
55 | break | |
56 | fi | |
57 | done | |
58 | ||
59 | #then, parse the options as they override the options from configFile | |
60 | for opt in "${args[@]}"; do | |
61 | [[ -n ${encodedSpaces} ]] && opt="$(decSpaces ${opt})" | |
62 | if [[ ! "${opt}" =~ .*=.* ]]; then | |
63 | echo "badly formatted option ${var}, should be: option=value, stopping..." | |
64 | return 1 | |
65 | fi | |
66 | local var="${opt%%=*}" | |
67 | local value="${opt#*=}" | |
68 | #echo "${var}=${value}" | |
69 | export ${var}="${value}" | |
70 | done | |
71 | return 0 | |
72 | } | |
73 | ||
74 | guessRunData() | |
75 | { | |
76 | #guess the period from the path, pick the rightmost one | |
21afcc52 | 77 | #if $ocdbStorage is set it will be reset to the anchorYear (for MC) |
3fc2dd01 | 78 | period="" |
79 | runNumber="" | |
80 | year="" | |
81 | pass="" | |
82 | legoTrainRunNumber="" | |
83 | dataType="" | |
84 | originalPass="" | |
85 | originalPeriod="" | |
86 | anchorYear="" | |
87 | shortRunNumber="" | |
88 | ||
89 | local oldIFS=${IFS} | |
90 | local IFS="/" | |
21afcc52 | 91 | [[ -z ${1} ]] && return 1 |
3fc2dd01 | 92 | declare -a path=( $1 ) |
93 | IFS="${oldIFS}" | |
94 | local dirDepth=$(( ${#path[*]}-1 )) | |
95 | for ((x=${dirDepth};x>=0;x--)); do | |
96 | ||
97 | [[ $((x-1)) -ge 0 ]] && local fieldPrev=${path[$((x-1))]} | |
98 | local field=${path[${x}]} | |
99 | local fieldNext=${path[$((x+1))]} | |
100 | ||
101 | [[ ${field} =~ ^[0-9]*$ && ${fieldNext} =~ (.*\.zip$|.*\.root$) ]] && legoTrainRunNumber=${field} | |
102 | [[ -n ${legoTrainRunNumber} && -z ${pass} ]] && pass=${fieldPrev} | |
103 | [[ ${field} =~ ^LHC[0-9][0-9][a-z].*$ ]] && period=${field%_*} && originalPeriod=${field} | |
104 | [[ ${field} =~ ^000[0-9][0-9][0-9][0-9][0-9][0-9]$ ]] && runNumber=${field#000} | |
105 | [[ ${field} =~ ^[0-9][0-9][0-9][0-9][0-9][0-9]$ ]] && shortRunNumber=${field} | |
106 | [[ ${field} =~ ^20[0-9][0-9]$ ]] && year=${field} | |
107 | [[ ${field} =~ ^(^sim$|^data$) ]] && dataType=${field} | |
108 | done | |
3fc2dd01 | 109 | originalPass=${pass} |
21afcc52 | 110 | |
111 | if [[ ${dataType} =~ sim ]]; then | |
112 | [[ -n ${shortRunNumber} && -z ${runNumber} ]] && runNumber=${shortRunNumber} | |
113 | pass="passMC" | |
114 | originalPass="" #for MC not from lego, the runNumber is identified as lego train number, thus needs to be nulled | |
3fc2dd01 | 115 | anchorYear=$(run2year $runNumber) |
116 | if [[ -z "${anchorYear}" ]]; then | |
117 | echo "WARNING: anchorYear not available for this production: ${originalPeriod}, runNumber: ${runNumber}. Cannot set the OCDB." | |
118 | return 1 | |
119 | fi | |
21afcc52 | 120 | #modify the OCDB: set the year |
3fc2dd01 | 121 | ocdbStorage=$(setYear ${anchorYear} ${ocdbStorage}) |
122 | else | |
123 | ocdbStorage=$(setYear ${year} ${ocdbStorage}) | |
124 | fi | |
125 | ||
21afcc52 | 126 | [[ -n ${shortRunNumber} && -z ${runNumber} && -z {dataType} ]] && runNumber=${shortRunNumber} |
127 | [[ -n ${shortRunNumber} && "${legoTrainRunNumber}" =~ ${shortRunNumber} ]] && legoTrainRunNumber="" | |
128 | [[ -z ${legoTrainRunNumber} && ${dataType} == "data" ]] && pass=${path[$((dirDepth-1))]} | |
129 | [[ -n ${legoTrainRunNumber} ]] && pass+="_lego${legoTrainRunNumber}" | |
130 | ||
3fc2dd01 | 131 | #if [[ -z ${dataType} || -z ${year} || -z ${period} || -z ${runNumber}} || -z ${pass} ]]; |
132 | if [[ -z ${runNumber} ]] | |
133 | then | |
134 | #error condition | |
135 | return 1 | |
136 | fi | |
137 | ||
138 | #ALL OK | |
139 | return 0 | |
140 | } | |
141 | ||
a510263c | 142 | guessRunNumber() |
143 | ( | |
144 | #guess the run number from the path, pick the rightmost one | |
145 | if guessRunData "${1}"; then | |
146 | echo ${runNumber} | |
147 | return 0 | |
148 | fi | |
149 | return 1 | |
150 | ) | |
151 | ||
152 | guessYear() | |
153 | ( | |
154 | #guess the year from the path, pick the rightmost one | |
155 | if guessRunData "${1}"; then | |
156 | echo ${year} | |
157 | return 0 | |
158 | fi | |
159 | return 1 | |
160 | ) | |
161 | ||
162 | guessPeriod() | |
163 | ( | |
164 | #guess the period from the path, pick the rightmost one | |
165 | if guessRunData "${1}"; then | |
166 | echo ${period} | |
167 | return 0 | |
168 | fi | |
169 | return 1 | |
170 | ) | |
171 | ||
3fc2dd01 | 172 | setYear() |
173 | { | |
06878fe9 | 174 | #set the year in the string |
175 | #usualy used to modify the year in $ocdbStorage | |
3fc2dd01 | 176 | # ${1} - year to be set |
177 | # ${2} - where to set the year | |
06878fe9 | 178 | #if AUTOYEAR is present in target - it will be replaced by the year |
179 | local yearSource=$(guessYearFast ${1}) | |
180 | local yearTarget=$(guessYearFast ${2}) | |
3fc2dd01 | 181 | local path=${2} |
06878fe9 | 182 | [[ ${yearSource} -ne ${yearTarget} && -n ${yearTarget} && -n ${yearSource} ]] \ |
4c0022d5 | 183 | && path=${2/\/"${yearTarget}"/\/"${yearSource}"} |
a62bb24d | 184 | path=${path/\/\//\/} |
185 | # The previous line would transform raw:// in raw:/ | |
186 | # The next fixes this | |
187 | echo ${path/%:\//:\/\/} | |
3fc2dd01 | 188 | return 0 |
189 | } | |
190 | ||
d2587a2f | 191 | guessYearFast() |
192 | { | |
193 | #guess the year from the path, pick the rightmost one | |
06878fe9 | 194 | #is string AUTOYEAR present, will be returned |
d2587a2f | 195 | local IFS="/" |
196 | declare -a pathArray=( ${1} ) | |
06878fe9 | 197 | local field="" |
198 | local year="" | |
199 | local autoYear="" | |
d2587a2f | 200 | for field in ${pathArray[@]}; do |
06878fe9 | 201 | [[ ${field} =~ ^20[0-9][0-9]$ ]] && year="${field}" |
202 | [[ ${field} == AUTOYEAR ]] && autoYear="${field}" | |
d2587a2f | 203 | done |
06878fe9 | 204 | [[ -n ${autoYear} ]] && year="${autoYear}" |
d2587a2f | 205 | echo ${year} |
206 | return 0 | |
207 | } | |
208 | ||
3fc2dd01 | 209 | run2year() |
210 | { | |
211 | #for a given run print the year. | |
212 | #the run-year table is ${PWGPP_runMap} (a string) | |
213 | #one line per year, format: year runMin runMax | |
214 | local run=$1 | |
215 | [[ -z ${run} ]] && return 1 | |
216 | local year="" | |
217 | local runMin="" | |
218 | local runMax="" | |
219 | while read year runMin runMax; do | |
220 | [[ -z ${year} || -z ${runMin} || -z ${runMax} ]] && continue | |
221 | [[ ${run} -ge ${runMin} && ${run} -le ${runMax} ]] && echo ${year} && break | |
222 | done < <(echo "${PWGPP_runMap}") | |
223 | return 0 | |
224 | } | |
225 | ||
226 | hostInfo(){ | |
227 | # | |
228 | # Hallo world - Print AliRoot/Root/Alien system info | |
229 | # | |
230 | ||
231 | # | |
232 | # HOST info | |
233 | # | |
234 | echo -------------------------------------- | |
235 | echo | |
236 | echo HOSTINFO | |
237 | echo | |
238 | echo HOSTINFO HOSTNAME" "$HOSTNAME | |
239 | echo HOSTINFO DATE" "`date` | |
240 | echo HOSTINFO gccpath" "`which gcc` | |
241 | echo HOSTINFO gcc version" "`gcc --version | grep gcc` | |
242 | echo -------------------------------------- | |
243 | ||
244 | # | |
245 | # ROOT info | |
246 | # | |
247 | echo -------------------------------------- | |
248 | echo | |
249 | echo ROOTINFO | |
250 | echo | |
251 | echo ROOTINFO ROOT" "`which root` | |
252 | echo ROOTINFO VERSION" "`root-config --version` | |
253 | echo | |
254 | echo -------------------------------------- | |
255 | ||
256 | ||
257 | # | |
258 | # ALIROOT info | |
259 | # | |
260 | echo -------------------------------------- | |
261 | echo | |
262 | echo ALIROOTINFO | |
263 | echo | |
264 | echo ALIROOTINFO ALIROOT" "`which aliroot` | |
265 | echo ALIROOTINFO VERSION" "`echo $ALICE_LEVEL` | |
266 | echo ALIROOTINFO TARGET" "`echo $ALICE_TARGET` | |
267 | echo | |
268 | echo -------------------------------------- | |
269 | ||
270 | # | |
271 | # Alien info | |
272 | # | |
273 | #echo -------------------------------------- | |
274 | #echo | |
275 | #echo ALIENINFO | |
276 | #for a in `alien --printenv`; do echo ALIENINFO $a; done | |
277 | #echo | |
278 | #echo -------------------------------------- | |
279 | ||
280 | # | |
281 | # Local Info | |
282 | # | |
283 | echo PWD `pwd` | |
284 | echo Dir | |
285 | ls -al | |
286 | echo | |
287 | echo | |
288 | echo | |
289 | ||
290 | return 0 | |
291 | } | |
292 | ||
293 | summarizeLogs() | |
294 | { | |
295 | #validate and summarize the status of logs | |
296 | #input is a list of logs, or a glob: | |
297 | #example (summarizes logs in current and subdirs): | |
298 | # summarizeLogs * */* | |
a510263c | 299 | #if no args given, process all files in PWD |
3fc2dd01 | 300 | #exit code 1 if some logs are not validated |
301 | ||
302 | #print a summary of logs | |
303 | local input | |
304 | local file="" | |
305 | declare -A files | |
306 | input=("${@}") | |
307 | [[ -z "${input[*]}" ]] && input=( "${PWD}"/* ) | |
308 | ||
309 | #double inclusion protection+make full paths | |
310 | for file in "${input[@]}"; do | |
07566ff3 | 311 | [[ ! "${file}" =~ ^/ ]] && file="${PWD}/${file}" |
3fc2dd01 | 312 | files["${file}"]="${file}" |
313 | done | |
314 | ||
315 | local logFiles | |
21630cdd | 316 | logFiles="\.*log$|^stdout$|^stderr$" |
3fc2dd01 | 317 | |
318 | #check logs | |
319 | local logStatus=0 | |
320 | local errorSummary="" | |
321 | local validationStatus="" | |
322 | declare -A coreFiles | |
323 | for file in "${files[@]}"; do | |
324 | [[ ! -f ${file} ]] && continue | |
325 | #keep track of core files for later processing | |
21630cdd | 326 | [[ "${file##*/}" =~ ^core$ ]] && coreFiles[${file}]="${file}" && continue |
327 | [[ ! "${file##*/}" =~ ${logFiles} ]] && continue | |
3fc2dd01 | 328 | errorSummary=$(validateLog ${file}) |
329 | validationStatus=$? | |
330 | [[ validationStatus -ne 0 ]] && logStatus=1 | |
331 | if [[ ${validationStatus} -eq 0 ]]; then | |
332 | #in pretend mode randomly report an error in rec.log some cases | |
333 | echo "${file} OK" | |
334 | elif [[ ${validationStatus} -eq 1 ]]; then | |
335 | echo "${file} BAD ${errorSummary}" | |
336 | elif [[ ${validationStatus} -eq 2 ]]; then | |
337 | echo "${file} OK MWAH ${errorSummary}" | |
338 | fi | |
339 | done | |
340 | ||
341 | #report core files | |
342 | for x in "${coreFiles[@]}"; do | |
343 | echo ${x} | |
344 | chmod 644 ${x} | |
07566ff3 | 345 | #gdb --batch --quiet -ex "bt" -ex "quit" aliroot ${x} > stacktrace_${x//\//_}.log |
346 | gdb --batch --quiet -ex "bt" -ex "quit" aliroot ${x} > stacktrace.log | |
3fc2dd01 | 347 | local nLines[2] |
07566ff3 | 348 | #nLines=($(wc -l stacktrace_${x//\//_}.log)) |
349 | nLines=($(wc -l stacktrace.log)) | |
3fc2dd01 | 350 | if [[ ${nLines[0]} -eq 0 ]]; then |
07566ff3 | 351 | #rm stacktrace_${x//\//_}.log |
352 | rm stacktrace.log | |
3fc2dd01 | 353 | else |
354 | logStatus=1 | |
07566ff3 | 355 | echo "${x%/*}/stacktrace.log" |
3fc2dd01 | 356 | fi |
357 | done | |
358 | ||
359 | return ${logStatus} | |
360 | } | |
361 | ||
362 | validateLog() | |
363 | { | |
364 | #validate one log file | |
365 | #input is path to log file | |
366 | #output an error summary on stdout | |
367 | #exit code is 0 if validated, 1 otherwise | |
368 | log=${1} | |
369 | errorConditions=( | |
370 | 'There was a crash' | |
371 | 'floating' | |
372 | 'error while loading shared libraries' | |
373 | 'std::bad_alloc' | |
374 | 's_err_syswatch_' | |
375 | 'Thread [0-9]* (Thread' | |
376 | 'AliFatal' | |
3fc2dd01 | 377 | '\.C.*error:.*\.h: No such file' |
378 | 'segmentation' | |
d5dfad3c | 379 | 'Segmentation fault' |
3fc2dd01 | 380 | 'Interpreter error recovered' |
381 | ': command not found' | |
382 | ': comando non trovato' | |
d5dfad3c | 383 | 'core dumped' |
3fc2dd01 | 384 | ) |
385 | ||
386 | warningConditions=( | |
387 | 'This is serious' | |
388 | ) | |
389 | ||
390 | local logStatus=0 | |
391 | local errorSummary="" | |
392 | local warningSummary="" | |
d5dfad3c | 393 | local errorCondition="" |
394 | for errorCondition in "${errorConditions[@]}"; do | |
395 | local tmp=$(grep -m1 -e "${errorCondition}" ${log}) | |
396 | local error="" | |
397 | [[ -n ${tmp} ]] && error=" : ${errorCondition}" | |
398 | errorSummary+=${error} | |
3fc2dd01 | 399 | done |
400 | ||
d5dfad3c | 401 | local warningCondition="" |
402 | for warningCondition in "${warningConditions[@]}"; do | |
403 | local tmp=$(grep -m1 -e "${warningCondition}" ${log}) | |
404 | local warning="" | |
405 | [[ -n ${tmp} ]] && warning=" : ${warningCondition}" | |
406 | warningSummary+=${warning} | |
3fc2dd01 | 407 | done |
408 | ||
409 | if [[ -n ${errorSummary} ]]; then | |
410 | echo "${errorSummary}" | |
411 | return 1 | |
412 | fi | |
413 | ||
414 | if [[ -n ${warningSummary} ]]; then | |
415 | echo "${warningSummary}" | |
416 | return 2 | |
417 | fi | |
418 | ||
419 | return 0 | |
420 | } | |
421 | ||
422 | mergeSysLogs() | |
423 | { | |
424 | if [[ $# -lt 2 ]]; then | |
425 | echo 'merge syslogs to an output file' | |
426 | echo 'usage:' | |
427 | echo 'mergeSysLogs outputFile inputFile1 inputFile2 ...' | |
428 | return 0 | |
429 | fi | |
430 | local outputFile | |
431 | local inputFiles | |
432 | local i | |
433 | local x | |
434 | local runNumber | |
435 | outputFile=${1} | |
436 | shift | |
437 | inputFiles="$@" | |
438 | i=0 | |
439 | if ! ls -1 ${inputFiles} &>/dev/null; then echo "the files dont exist!: ${inputFiles}"; return 1; fi | |
440 | while read x; do | |
441 | runNumber=$(guessRunNumber ${x}) | |
442 | [[ -z ${runNumber} ]] && echo "run number cannot be guessed for ${x}" && continue | |
443 | awk -v run=${runNumber} -v i=${i} 'NR > 1 {print run" "$0} NR==1 && i==0 {print "run/I:"$0}' ${x} | |
444 | (( i++ )) | |
445 | done < <(ls -1 ${inputFiles}) > ${outputFile} | |
446 | return 0 | |
447 | } | |
448 | ||
449 | stackTraceTree() | |
450 | { | |
451 | if [[ $# -lt 1 ]]; then | |
452 | echo 'make stacktrace processing in case of standard root crash log' | |
453 | echo 'input is a (list of) text files with the stack trace (either gdb aoutput' | |
454 | echo 'produced with e.g. gdb --batch --quiet -ex "bt" -ex "quit" aliroot core,' | |
455 | echo 'or the root crash log), output is a TTree formatted table.' | |
456 | echo 'example usage:' | |
457 | echo 'benchmark.sh stackTraceTree /foo/*/rec.log' | |
458 | echo 'benchmark.sh stackTraceTree $(cat file.list)' | |
459 | echo 'benchmark.sh stackTraceTree `cat file.list`' | |
460 | return 0 | |
461 | fi | |
07566ff3 | 462 | #cat "${@}" | gawk ' |
3fc2dd01 | 463 | gawk ' |
464 | BEGIN { | |
07566ff3 | 465 | print "frame/I:method/C:line/C:cpass/I:aliroot/I:file/C"; |
3fc2dd01 | 466 | RS="#[0-9]*"; |
467 | aliroot=0; | |
468 | read=1; | |
469 | } | |
470 | /There was a crash/ {read=1;} | |
471 | /The lines below might hint at the cause of the crash/ {read=0;} | |
472 | read==1 { | |
473 | if ($3 ~ /Ali*/) aliroot=1; else aliroot=0; | |
474 | gsub("#","",RT); | |
475 | if ($NF!="" && RT!="" && $3!="") print RT" "$3" "$NF" "0" "aliroot" "FILENAME | |
476 | } | |
07566ff3 | 477 | ' "${@}" 2>/dev/null |
478 | } | |
479 | ||
480 | plotStackTraceTree() | |
481 | { | |
482 | #plot the stacktrace tree, | |
483 | #first arg is the text file in the root tree format | |
484 | #second arg is optional: a plot is written to file instead of screen | |
d5dfad3c | 485 | #third arg is optional: selection for plotting, default skip G_ stuff |
07566ff3 | 486 | local tree=$1 |
487 | local plot=${2:-"crashes.png"} | |
d5dfad3c | 488 | local selection=${3:-'!strstr(method,\"G__\")'} |
06c216e0 | 489 | [[ ! -f ${tree} ]] && echo "plotStackTraceTree: no input file given" && return 1 |
07566ff3 | 490 | aliroot -b <<EOF |
491 | TTree* t=AliSysInfo::MakeTree("${tree}"); | |
492 | TCanvas* canvas = new TCanvas("QA crashes","QA crashes",1); | |
d5dfad3c | 493 | t->Draw("method","${selection}",""); |
07566ff3 | 494 | canvas->SaveAs("${plot}"); |
495 | .q | |
496 | EOF | |
497 | return 0 | |
3fc2dd01 | 498 | } |
499 | ||
500 | encSpaces() | |
501 | { | |
502 | echo "${1// /±@@±}" | |
503 | } | |
504 | ||
505 | decSpaces() | |
506 | { | |
507 | echo "${1//±@@±/ }" | |
508 | } | |
509 | ||
07566ff3 | 510 | get_realpath() |
511 | { | |
512 | if [[ $# -lt 1 ]]; then | |
a510263c | 513 | echo "print the full path of a file or directory, like \"readlink -f\" on linux" |
07566ff3 | 514 | echo "Usage:" |
a510263c | 515 | echo " get_realpath <someFileOrDir>" |
07566ff3 | 516 | return 0 |
517 | fi | |
518 | if [[ -f "$1" ]] | |
519 | then | |
520 | # file *must* exist | |
521 | if cd "$(echo "${1%/*}")" &>/dev/null | |
522 | then | |
523 | # file *may* not be local | |
524 | # exception is ./file.ext | |
525 | # try 'cd .; cd -;' *works!* | |
526 | local tmppwd="$PWD" | |
527 | cd - &>/dev/null | |
528 | else | |
529 | # file *must* be local | |
530 | local tmppwd="$PWD" | |
531 | fi | |
a510263c | 532 | elif [[ -d "$1" ]]; then |
533 | if cd "$1" &>/dev/null; then | |
534 | local tmppwd="$PWD" | |
535 | cd - &>/dev/null | |
536 | echo "$tmppwd" | |
537 | return 0 | |
538 | else | |
539 | return 1 | |
540 | fi | |
07566ff3 | 541 | else |
542 | # file *cannot* exist | |
543 | return 1 # failure | |
544 | fi | |
545 | # reassemble realpath | |
546 | echo "$tmppwd"/"${1##*/}" | |
547 | return 0 # success | |
548 | } | |
549 | ||
550 | printLogStatistics() | |
551 | { | |
552 | #this function processes the summary logs and prints some stats | |
553 | #relies on the summary log format produced by summarizeLogs() | |
554 | # - how many checked logs in total | |
555 | # - number of each type of problem | |
556 | # example usage: | |
557 | # printLogStatistics */*.log | |
558 | [[ ! -f $1 ]] && return 1 | |
d5dfad3c | 559 | echo "log statistics from: ${1%/*}" |
07566ff3 | 560 | #cat "${@}" | awk ' |
561 | awk ' | |
d5dfad3c | 562 | BEGIN {nOK=0; nCores=0; nStackTraces=0;} |
07566ff3 | 563 | /\/core/ {nCores++} |
564 | /\/stacktrace.log/ {nStackTraces++} | |
565 | /OK/ {nOK++; nLogs++;} | |
566 | /BAD/ { | |
567 | nLogs++ | |
568 | err="" | |
569 | write=0 | |
570 | for (i=3; i<=NF; i++) | |
571 | { | |
2fe76e43 | 572 | if ($i ~ /^\:$/) |
07566ff3 | 573 | write=1 |
574 | else | |
575 | write=0 | |
576 | ||
577 | if (write==0) | |
578 | { | |
579 | if (err=="") err=$i | |
580 | else err=(err FS $i) | |
581 | } | |
582 | ||
583 | if (err != "" && (write==1 || i==NF)) | |
584 | { | |
585 | sumBAD[err]++ | |
586 | err="" | |
587 | } | |
588 | } | |
589 | } | |
590 | END { | |
591 | print ("number of succesful jobs: " nOK" out of "nLogs ) | |
592 | for (key in sumBAD) | |
593 | { | |
594 | print key": "sumBAD[key] | |
595 | } | |
596 | if (nCores>0) print "core files: "nCores", stack traces: "nStackTraces | |
597 | } | |
598 | ' "${@}" | |
599 | } | |
39b88d90 | 600 | |
601 | createUniquePID() | |
602 | { | |
603 | #create a unique ID for jobs running in parallel | |
604 | #consists of the ip address of the default network interface, PID, | |
605 | #if an argument is given, append it (e.g. a production ID) | |
606 | #the fields are space separated with a tag for easy parsing | |
607 | #spaces in the productionID will be encoded using encSpaces() | |
608 | local productionID="" | |
609 | [[ -n "${1}" ]] && productionID=$(encSpaces "${1}") | |
610 | local defaultIP=$(/sbin/route | awk '$1=="default" {print $8}' | xargs /sbin/ifconfig | awk '/inet / {print $2}' | sed 's/.*\([0-9]?\.[0-9]?\.[0-9]?\.[0-9]?\)/$1/') | |
611 | local id="ip:${defaultIP} pid:${BASHPID}" | |
612 | [[ -n "${productionID}" ]] && id+=" prod:${productionID}" | |
613 | echo "${id}" | |
614 | } | |
e0f33210 | 615 | |
a510263c | 616 | copyFileToLocal() |
e0f33210 | 617 | ( |
a510263c | 618 | #copies a single file to a local destination: the file may either come from |
619 | #a local filesystem or from a remote location (whose protocol must be | |
620 | #supported) | |
621 | #copy is "robust" and it is repeated some times in case of failure before | |
622 | #giving up (1 is returned in that case) | |
92092385 | 623 | #origin: Dario Berzano, dario.berzano@cern.ch |
a510263c | 624 | src="$1" |
625 | dst="$2" | |
626 | ok=0 | |
627 | [[ -z "${maxCopyTries}" ]] && maxCopyTries=10 | |
628 | ||
629 | proto="${src%%://*}" | |
630 | ||
631 | echo "copy file to local dest started: $src -> $dst" | |
632 | ||
633 | for (( i=1 ; i<=maxCopyTries ; i++ )) ; do | |
634 | ||
635 | echo "...attempt $i of $maxCopyTries" | |
636 | rm -f "$dst" | |
637 | ||
638 | if [[ "$proto" == "$src" ]]; then | |
639 | cp "$src" "$dst" | |
640 | else | |
641 | case "$proto" in | |
642 | root) | |
643 | xrdcp -f "$src" "$dst" | |
644 | ;; | |
645 | http) | |
646 | curl -L "$src" -O "$dst" | |
647 | ;; | |
648 | *) | |
649 | echo "protocol not supported: $proto" | |
650 | return 2 | |
651 | ;; | |
652 | esac | |
653 | fi | |
654 | ||
655 | if [ $? == 0 ] ; then | |
656 | ok=1 | |
657 | break | |
658 | fi | |
659 | ||
660 | done | |
661 | ||
662 | if [[ "$ok" == 1 ]] ; then | |
663 | echo "copy file to local dest OK after $i attempt(s): $src -> $dst" | |
e0f33210 | 664 | return 0 |
665 | fi | |
a510263c | 666 | |
667 | echo "copy file to local dest FAILED after $maxCopyTries attempt(s): $src -> $dst" | |
668 | return 1 | |
669 | ) | |
670 | ||
671 | paranoidCp() | |
672 | ( | |
673 | #recursively copy files and directories | |
674 | #if target is a directory - it must exist! | |
675 | #to avoid using find and the like as they kill | |
676 | #the performance on some cluster file systems | |
677 | #does not copy links to avoid problems | |
678 | sourceFiles=("${@}") | |
679 | destination="${sourceFiles[@]:(-1)}" #last element | |
680 | unset sourceFiles[${#sourceFiles[@]}-1] #remove last element (dst) | |
681 | #[[ ! -f "${destination}" ]] | |
682 | for src in "${sourceFiles[@]}"; do | |
683 | if [[ -f "${src}" && ! -h "${src}" ]]; then | |
684 | paranoidCopyFile "${src}" "${destination}" | |
685 | elif [[ -d "${src}" && ! -h "${src}" ]]; then | |
686 | src="${src%/}" | |
687 | dst="${destination}/${src##*/}" | |
688 | mkdir -p "${dst}" | |
689 | paranoidCp "${src}"/* "${dst}" | |
690 | fi | |
691 | done | |
692 | ) | |
693 | ||
694 | paranoidCopyFile() | |
695 | ( | |
696 | #copy a single file to a target in an existing dir | |
697 | #repeat a few times if copy fails | |
698 | #returns 1 on failure, 0 on success | |
699 | src=$(get_realpath "${1}") | |
700 | dst=$(get_realpath "${2}") | |
701 | [[ -d "${dst}" ]] && dst="${dst}/${src##*/}" | |
702 | #some sanity check | |
703 | [[ -z "${src}" ]] && echo "$1 does not exist" && return 1 | |
704 | [[ -z "${dst}" ]] && echo "$2 does not exist" && return 1 | |
705 | #check if we are not trying to copy to the same file | |
706 | [[ "${src}" == "${dst}" ]] && echo "$dst==$src, not copying" && return 0 | |
707 | ok=0 | |
708 | [[ -z "${maxCopyTries}" ]] && maxCopyTries=10 | |
709 | ||
710 | echo "paranoid copy started: $src -> $dst" | |
711 | for (( i=1 ; i<=maxCopyTries ; i++ )) ; do | |
712 | ||
713 | echo "...attempt $i of $maxCopyTries" | |
714 | rm -f "$dst" | |
715 | cp "$src" "$dst" | |
716 | ||
717 | cmp -s "$src" "$dst" | |
718 | if [ $? == 0 ] ; then | |
719 | ok=1 | |
720 | break | |
721 | fi | |
722 | ||
723 | done | |
724 | ||
725 | if [[ "$ok" == 1 ]] ; then | |
726 | echo "paranoid copy OK after $i attempt(s): $src -> $dst" | |
727 | return 0 | |
728 | fi | |
729 | ||
730 | echo "paranoid copy FAILED after $maxCopyTries attempt(s): $src -> $dst" | |
e0f33210 | 731 | return 1 |
732 | ) | |
733 | ||
da387e6e | 734 | generPWD(){ |
735 | # | |
736 | # generate semirandom pwd using 2 keys | |
737 | # Example usage: | |
738 | # generPWD myserviceaccount10 key11 | |
739 | key0=$1 | |
740 | key1=$2 | |
741 | heslo0=`md5sum <<< "$key0 $key1" | cut -c 1-16` | |
742 | heslo=`echo $heslo0 | cut -c 1-8| awk '{print toupper($0)}'` | |
743 | heslo=$heslo`echo $heslo0 | cut -c 8-15| awk '{print tolower($0)}'`% | |
744 | echo $heslo; | |
745 | } | |
746 | ||
f2e3b505 | 747 | #this makes debugging easier: |
748 | #executes the command given as an argument in this environment | |
749 | #use case: | |
750 | # bashdb utilities.sh summarizeLogs * */* | |
751 | [[ $# != 0 ]] && eval "$@" |