9 from DataQualityUtils.dqu_subprocess
import apply
as _local_apply
19 from ROOT
import gSystem
21 from DataQualityUtils.handimod
import handiWithComparisons
22 from DataQualityUtils.handimod
import makeCSSFile
23 from DataQualityUtils.SingleAppInstance
import SingleAppInstance
24 from DataQualityUtils.hancoolmod
import hancool
25 from DataQualityUtils.DQHistogramMergeMod
import DQHistogramMerge
26 import DataQualityUtils.HanMetadata
28 gSystem.Load(
"libdqm_core")
29 gSystem.Load(
"libDataQualityInterfaces")
30 from ROOT
import dqutils
35 VERSION =
'$Id: DQWebDisplay.py 529090 2012-12-05 22:32:03Z ponyisi $'
36 FROMEMAIL =
'atlasdqm@cern.ch'
43 os.environ[
'TDAQ_ERS_NO_SIGNAL_HANDLERS'] =
'1'
48 super(LockAcquisitionException,self).
__init__(msg)
59 if isinstance(c.server, str):
65 if c.server != []
or c.webHandoffDir !=
"" or c.lockFile ==
'':
67 print(
"Lockfile is disabled")
73 instance = SingleAppInstance( c.htmlDir +
"/" + c.lockFile,
True )
74 islocked = instance.acquire()
75 except SingleAppInstance.FileLockAcquisitionError
as e:
76 print(
'=========================================================================')
77 print(
'Cannot acquire lock on', c.htmlDir)
78 print(
'This usually means either')
79 print(
' -> the directory does not exist,')
80 print(
' -> you do not have the required permissions, or')
81 print(
' -> the directory is out of space.')
82 print(
'If you ran into this error while trying to test the web display, please')
83 print(
'read the instructions at:')
84 print(
'https://twiki.cern.ch/twiki/bin/view/Atlas/DQOperationalRecipes#Obtain_SVN_and_disk_write_permis')
86 print(
'Explicit error:', e)
87 print(
'=========================================================================')
91 print(
"Another instance is running; waiting 60 seconds...")
101 allDirsScriptLoc = c.htmlWeb
102 runlistLoc = c.htmlWeb +
"/" + c.runlist
108 if ( c.hanResultsDir.rfind(
"/")!=(len(c.hanResultsDir)-1) ):
111 if ( c.htmlDir.rfind(
"/")!=(len(c.htmlDir)-1) ):
114 inputFileName = inputFilePath
115 i = inputFilePath.rfind(
"/")
117 inputFileName = inputFilePath[i+1:]
120 shortStream =
"NoStream"
122 procpass =
int(sys.argv[3])
124 if c.config ==
"RTT":
125 shortStream = time.strftime(
"%A")
127 fields = inputFileName.split(
".")
129 runid =
int(fields[1])
130 shortStream = fields[2]
136 print(
"Searching for existing histogram cache to merge with input histograms...")
138 inputFilePath = _local_apply(mergeAndCache, ( inputFilePath, runid, shortStream, c.histogramCache ) )
139 except LockAcquisitionException:
141 shortStream =
"tmp_" + shortStream
142 elif c.histogramCache !=
"":
143 cacheFile, version =
findCacheFile( inputFilePath, runid, shortStream, c.histogramCache )
146 print(
"Removing cached histograms used during accumulation mode")
148 while cacheFile !=
'':
149 fullCachePath = c.histogramCache +
"/" + cacheFile
150 os.unlink( fullCachePath )
151 cacheFile, version =
findCacheFile( inputFilePath, runid, shortStream, c.histogramCache )
156 if len(sys.argv) >= 5:
157 stream =
repr(procpass) +
"/" + shortStream
159 outputHanResultsDir = c.hanResultsDir + stream +
'/run_' +
repr(runid)
160 outputHtmlDir = c.htmlDir + stream +
"/"
162 if c.server != []
or c.webHandoffDir !=
"" or c.eosResultsDir:
163 print(
"Writing all output to \'./\'; will copy at the end to ", end=
'')
164 if c.webHandoffDir !=
"":
165 print(
"a handoff directory:", c.webHandoffDir)
167 print(
"the web server(s):",
', '.
join(c.server))
169 outputHanResultsDir =
"./han_results/" + stream +
'/run_' +
repr(runid)
170 outputHtmlDir =
"./www/" + stream +
"/"
175 total=_local_apply(getHanResults, ( inputFilePath, outputHanResultsDir, inputFilePath, c.hcfg, c.hcfg_min10, c.hcfg_min30 ))
176 fileList=total.rsplit(
'\n')
177 if amitag
is not None:
181 if (len(fileList[number-1])<1):
185 runfile=fileList[0].rsplit()
186 if (len(runfile) == 0):
187 print(
"ERROR: TFile has no \"run_*\" directories. The input monitoring file is not organized for production use,")
188 print(
"probably because AthenaMonitoring is not configured properly. Exiting.\n")
192 for allLines
in fileList:
193 splitLine = allLines.rsplit()
194 if len(splitLine) >= 1:
195 xferFileList.append( splitLine[0] +
"\n" )
198 runNumber = runfile[1]
199 rN=runNumber.lstrip(
"run_")
200 if not runAccumulating:
201 print(
"Getting COOL authentications")
210 if 'COOLUPLOADS' in os.environ:
211 uploadAllowed = (os.environ[
'COOLUPLOADS'] ==
'1')
215 if not uploadAllowed:
216 print(
'hancool run and upload to DB switched off by request')
218 if (uploadAllowed
and c.dbConnection):
220 print(
"Now calling hancool ...")
222 if '_' in stream: stream = stream.split(
'_',1)[-1]
223 if amitag
is not None and 'x' in amitag
and stream.startswith(
'express'):
224 dbTagName = c.dbTagNameESn
227 dbTagName = c.dbTagName
231 uploadTag = dbTagName % {
'stream': stream,
233 'procpass': procpass }
236 uploadTag = dbTagName
237 doUpload = (
'-%s-' % stream
in uploadTag)
240 print(
'isESn?', isESn)
241 _local_apply(hancool, (
int(rN),outputHanResultsDir,c.dbConnection,isESn))
246 for server
in c.server:
247 print(
"Transfering han files to server: ", server)
254 print(
"FAILED!", end=
'')
256 email(
'The transfer of han files\n\n' +
257 ''.
join(xferFileList) +
258 '\nto server ' + server +
259 ' failed. This may indicate that this server is down.\n'
260 'Please investigate as soon as possible!',
261 'WARNING! File transfer from Tier-0 failed',
263 'hn-atlas-data-quality-operations@cern.ch'
265 print(
"Email sent...")
269 if failures == len(c.server):
270 print(
"SERIOUS PROBLEM: file transfers failed to ALL defined servers")
272 print(
"Will die so as to alert Tier-0 shifter")
273 raise IOError(
'tarfile ssh transfer failed')
274 if c.eosResultsDir !=
"":
275 print(
"Transfering han files to EOS")
278 while failures < (eos_attempts+1) :
279 success_EOS =
transferFilesToEOS( xferFileList[:],
"./han_results/", c.eosResultsDir )
289 raise IOError(
"Transfer to /eos failed after {} attempts".
format(failures))
291 email(
'The transfer of han files\n\n' +
292 ''.
join(xferFileList) +
294 'Please investigate as soon as possible!',
295 'WARNING! File transfer from Tier-0 failed',
297 'hn-atlas-data-quality-operations@cern.ch'
299 print(
"Email sent...")
305 rundir=outputHtmlDir+runNumber+
"/"
309 now = time.localtime()
310 lastUpdate =
"Last Update: "+time.strftime(
'%Y-%m-%d %H:%M %Z', now)
313 g=
open(outputHtmlDir+runNumber +
'/index.html',
'w')
314 g.write(
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n')
315 g.write(
'<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n')
317 g.write(
'<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />\n')
318 g.write(
'<title>run ' +rN+
' ' + stream +
'</title>\n')
319 g.write(
'<link rel="stylesheet" href="AutomChecks.css" type="text/css" />\n')
322 g.write(
'<font class="DQGroup">[<a href="#" onclick="history.go(-1);return false;">Back</a>]</font>\n')
323 g.write(
'<h1>Run '+rN+
', ' + stream +
'</h1>\n\n')
330 for x
in range(0,number):
331 sp=fileList[x].rsplit()
333 print(
"Running handi on " + sp[0] +
":")
334 print(
'handi("Run '+rN+
', '+ stream +
'",' + sp[0] +
','+rundir+
'/run)')
335 _local_apply(handiWithComparisons, ( (
'Run '+rN+
', ' + stream), sp[0], (rundir+
"/run"), runlistLoc, compare, browserMenu, allDirsScriptLoc) )
338 if sp[1].
find(
"lowStat")!=-1:
339 print(
"Running handi on " + sp[0] +
":")
340 print(
'handi("Run '+rN+
', '+sp[1]+
', ' + stream +
'",' + sp[0] +
','+rundir+sp[3]+
')')
341 _local_apply(handiWithComparisons, ( (
'Run '+rN+
', '+sp[1]+
', ' + stream), sp[0], (rundir+sp[3]), runlistLoc, compare, browserMenu, allDirsScriptLoc) )
343 mN = sp[1].removeprefix(
"lowStat_")
344 min10List.append( (sp[3], mN) )
345 elif sp[1].
find(
"medStat")!=-1:
346 print(
"Running handi on " + sp[0] +
":")
347 print(
'handi("Run '+rN+
', '+sp[1]+
', ' + stream +
'",' + sp[0] +
','+rundir+sp[3]+
')')
348 _local_apply(handiWithComparisons, ((
'Run '+rN+
', '+sp[1]+
', ' + stream), sp[0], (rundir+sp[3]), runlistLoc, compare, browserMenu, allDirsScriptLoc))
350 mN = sp[1].removeprefix(
"medStat_")
351 min30List.append( (sp[3], mN) )
358 if len(min10List) == 0
and len(min30List) == 0:
360 g.write(
' <td width=120>\n')
361 g.write(
' <a href="run/index.html">Entire Run</a>\n')
364 elif len(min10List) == 0
or len(min30List) == 0:
367 if len(min10List) == 0:
369 blockName =
"medium stat interval"
372 blockName =
"low stat interval"
374 g.write(
' <td rowspan='+
str(len(minList)) +
' valign="top" width=120>\n')
375 g.write(
' <a href="run/index.html">Entire Run</a>\n')
379 for page, nMin
in minList:
381 g.write(
' <td width=200>\n')
382 if nMin.find(
'merged_')!=-1:
383 g.write(
' <a href="' + page +
'/index.html">' + nMin +
'</a>\n')
385 g.write(
' <a href="' + page +
'/index.html">' + blockName +
' ' + nMin +
'</a>\n')
387 margin =
'</tr>\n<tr>\n'
391 g.write(
' <td rowspan='+
str(len(min10List)) +
' valign="top" width=120>\n')
392 g.write(
' <a href="run/index.html">Entire Run</a>\n')
397 for page10, nMin10
in min10List:
401 iMin30 = (count // 3)
402 page30, nMin30 = min30List[iMin30]
403 g.write(
' <td rowspan=3 valign="top" width=200>\n')
404 g.write(
' <a href="' + page30 +
'/index.html">medium stat interval ' + nMin30 +
'</a>\n')
406 g.write(
' <td width=200>\n')
407 g.write(
' <a href="' + page10 +
'/index.html">low stat interval ' + nMin10 +
'</a>\n')
410 margin =
'</tr>\n<tr>\n'
413 g.write(
'</table>\n')
416 g.write(
'<br/>\n<font class=\"Note\">'+lastUpdate+
'</font><br />\n')
417 g.write(
'</body>\n</html>')
420 if c.webHandoffDir !=
"":
421 print(
'Transfering web files to handoff directory')
425 for server
in c.server:
426 print(
"Transfering web files to server: ", server)
434 email(
'The transfer of web files\n'
436 '\nto server' + server +
437 'failed. This may indicate that this server is down.\n'
438 'Please investigate as soon as possible!',
439 'WARNING! File transfer from Tier-0 failed',
441 'hn-atlas-data-quality-operations@cern.ch'
445 if failures == len(c.server):
446 print(
"SERIOUS PROBLEM: web files transfer failed to ALL defined servers")
448 print(
"Will die so as to alert Tier-0 shifter")
449 raise IOError(
'Directory ssh transfer failed')
454 if c.webHandoffDir ==
'':
455 print(
"Generating index files...")
456 for server
in c.server:
460 os.unlink(inputFilePath)
462 if instance
is not None:
468 if(
not os.access(dirname,os.F_OK) ):
473 print(
'Cannot create directory "' + dirname +
'"; exiting.')
479 rv = of.getHanResults(*args)
484 print(
"Cannot use cache: No cache directory defined")
491 for i
in range(MAX_LOCK_TRIES):
493 lockfilename = os.path.join(cache,
'lock_%s_%s' % (run, stream))
494 instance = SingleAppInstance( lockfilename,
True )
495 islocked = instance.acquire()
496 except SingleAppInstance.FileLockAcquisitionError
as e:
497 print(
'Unable to start to acquire cache directory lock! Bailing')
502 print(
'Unable to acquire cache directory lock; waiting 60 seconds; try', (i+1))
508 cacheFile, version =
findCacheFile( inputFilePath, run, stream, cache )
511 print(
"Found cached histograms: ")
512 print(
" dir: ", cache)
513 print(
" file: ", cacheFile)
514 fullCachePath = cache +
"/" + cacheFile
516 print(
"Did not find cached histograms: ")
517 print(
" dir: ", cache)
519 inputFileName = inputFilePath
520 i = inputFilePath.rfind(
"/")
522 inputFileName = inputFilePath[i+1:]
523 updatedFile = inputFileName +
".CACHE_" +
str(version+1)
524 print(
"Creating updated cache: ")
525 print(
" file: ", updatedFile)
526 fullUpdatedFile = cache +
"/" + updatedFile
529 if fullCachePath !=
'':
530 print(
'Copying previous cache to local directory ...', end=
'')
531 shutil.copy(fullCachePath, cacheFile)
534 mergeListName =
"cache_merge.list"
535 f =
open( mergeListName,
'w' )
537 txtstr +=
"%s\n" % cacheFile
538 txtstr +=
"%s\n" % inputFilePath
542 print(
"Running DQHistogramMerge...")
544 print(
"Finished DQHistogramMerge.")
547 if fullCachePath !=
'':
548 print(
'Deleting local copy of old cache ...', end=
'')
552 print(
'Copying new cache to cache directory ...', end=
'')
553 shutil.copy(updatedFile, fullUpdatedFile)
563 os.unlink( mergeListName )
564 if fullCachePath !=
"":
565 os.unlink( fullCachePath )
569 print(
'Now running histogram postprocessing ...')
570 from DataQualityUtils
import DQPostProcessMod
571 DQPostProcessMod.DQPostProcess( updatedFile, isIncremental=
True )
576 f = ROOT.TFile(inputFile,
'READ')
578 if f.Get(
'run_%s' % run):
582 print(
'WARNING: cache file %s appears to be corrupted' % inputFile)
587 for root, dirs, files
in os.walk(cache):
590 removeDir.append(name)
591 for fileName
in files:
592 if fileName.find(
str(run)) == -1:
594 if fileName.find(stream) == -1:
596 vi = fileName.rfind(
".CACHE_")
599 v =
int(fileName[vi+7:])
600 fileDict[v] = fileName
603 for name
in removeDir:
605 for v
in reversed(
sorted([key
for key
in fileDict.keys()
if verifyHasRunKey(cache+
'/'+fileDict[key], run)])):
606 return fileDict[v], v
612 import time, shutil, glob
613 import six.moves.configparser
as configparser
614 targetfname =
repr(
int(time.time())) +
'-' +
repr(os.getpid()) \
615 +
'-' + os.uname()[1] +
'.tgz'
616 targetfile = os.path.join(targetDir, targetfname)
618 print(
'Creating tarball', targetfname,
'...')
619 parser = configparser.ConfigParser()
620 parser.set(
'DEFAULT',
'target', config.htmlDir)
621 parser.add_section(
'execute')
622 parser.set(
'execute',
'command', config.htmlDir +
'/generateDQIndexFiles.py')
623 parser.set(
'execute',
'options',
'"%s" "%s" "%s" "%s" "%s"' % (config.htmlDir, config.config, config.indexFile, config.runlist, config.htmlWeb))
624 dnames = glob.glob(
'%s/*/*/*' % localDir)
626 print(
'Unexpected glob result')
628 parser.add_section(
'webdisplay')
629 parser.set(
'webdisplay',
'id', dnames[0][len(localDir):])
630 manifest =
open(localDir +
'/MANIFEST',
'w')
631 parser.write(manifest); manifest.close()
638 print(
'About to execute', end=
'')
639 cmd =
'cd %s ; tar czf %s MANIFEST %s ; mv %s ..' % (localDir, targetfname, dirName.replace(localDir,
''), targetfname)
643 raise IOError(
'Unable to create tarfile')
647 print(
'Copying tarball to', targetDir,
'...', end=
'')
648 shutil.copy(targetfname, targetfile)
650 print(
'Removing local tarball copy ...', end=
'')
651 os.unlink(targetfname)
655 username =
"atlasdqm"
656 if 'USER' in os.environ.keys():
657 username = os.environ[
'USER']
659 dirName = dirName.replace(localDir,
"")
662 cmd +=
"tar -czf - -C " + localDir +
" " + dirName
664 cmd +=
"ssh -l " + username +
" " + server +
" -x \"umask 002; cd " + targetDir +
" ; tar -xzf - \""
667 rv = os.system( cmd )
673 if config.webHandoffDir !=
'':
675 if config.server ==
'':
676 os.system(
'touch ' + os.path.join(dirName,
'complete'))
678 dirName = dirName.replace(localDir,
'')
679 username =
"atlasdqm"
680 if 'USER' in os.environ.keys():
681 username = os.environ[
'USER']
682 cmd =
"ssh -l " + username +
" " + config.server +
" -x \"umask 002; cd " + os.path.join(targetDir, dirName) +
" ; touch complete\""
685 rv = os.system( cmd )
687 raise IOError(
'Directory complete transfer marking failed')
691 username =
"atlasdqm"
692 if 'USER' in os.environ.keys():
693 username = os.environ[
'USER']
694 tarFileListName =
"./tarFileList.tmp"
695 t =
open( tarFileListName,
'w' )
696 for xferFile
in fileList:
697 os.system(
"chmod 664 " + xferFile )
698 xferFile = xferFile.replace(localDir,
"")
704 cmd += (
"tar -czf - -C %s -T %s" % (localDir, tarFileListName))
706 cmd +=
"ssh -l " + username +
" " + server +
" -x \"umask 002; cd " + targetDir +
" ; tar -xzf - \""
709 rv = os.system( cmd )
710 os.unlink(tarFileListName)
716 os.system(
'export XRD_REQUESTTIMEOUT=10')
718 for xferFile
in fileList:
719 xferFile = xferFile.rstrip()
720 os.system(
"chmod 664 " + xferFile )
721 file_name = xferFile.replace(localDir,
"")
723 eos =
"xrdcp --force --path --silent " + xferFile +
" "+ os.path.join(eosResultsDir, file_name)
726 run_eos += os.system( eos )
731 username =
"atlasdqm"
732 if 'USER' in os.environ.keys():
733 username = os.environ[
'USER']
735 filePath = filePath.replace(localDir,
"")
738 cmd +=
"cd " + localDir
740 cmd +=
"ssh -l " + username +
" " + server +
" -x \"cd " + remoteDir +
" ; cat " + filePath +
"\""
741 cmd +=
" > " + filePath
744 rv = os.system( cmd )
746 raise IOError(
'file retrieve failed')
749 username =
"atlasdqm"
750 if 'USER' in os.environ.keys():
751 username = os.environ[
'USER']
756 cmd +=
"ssh -l " + username +
" " + server +
" -x \"umask 002; "
757 cmd += installPath +
"/generateDQIndexFiles.py " + installPath +
" " + project +
" " + indexFile +
" "
758 cmd += runListFile +
" " + htmlAddress +
"\""
760 cmd += installPath +
"/generateDQIndexFiles.py " + installPath +
" " + project +
" " + indexFile +
" "
761 cmd += runListFile +
" " + htmlAddress
764 return os.system( cmd ) == 0
767 from DataQualityConfigurations
import getmodule
768 print(
'getting configuration', modname)
771 def email(msg, subject, whofrom, addressees):
773 from email.mime.text
import MIMEText
774 if isinstance(addressees, str):
775 addressees = [addressees]
776 email = MIMEText(msg)
777 email[
'Subject'] = subject
778 email[
'From'] = whofrom
779 email[
'To'] =
','.
join(addressees)
780 serv = smtplib.SMTP()
782 serv.sendmail(whofrom, addressees, email.as_string())
786 fileList = [x.split()[0]
for x
in fileList
if x !=
'']
787 print(
'Appending AMI information to metadata; tag =', amitag)
789 rf = ROOT.TFile.Open(f,
'UPDATE')
790 DataQualityUtils.HanMetadata.addMetadata(rf,
'AMI', {
'AMI Tag': amitag})
794 cmdi = sys.argv[0].rfind(
"/")
795 cmd = sys.argv[0][cmdi+1:]
797 print(
"Usage: ", cmd,
"<data_file> <config> <processing_version> [run_accumulating [conditions_string]]")
799 print(
"This is a production utility; use TEST config for development and testing.")
801 print(
"Processing version is an integer, starting from 1 (not 0)")
804 if __name__ ==
"__main__":
805 if len(sys.argv) < 4
or len(sys.argv) > 7:
809 inputFile = sys.argv[1]
810 runAccumulating =
False
811 if len(sys.argv)
in (6,7):
812 if sys.argv[4] ==
"True" or sys.argv[4] ==
"1":
813 runAccumulating =
True
815 if len(sys.argv) == 7:
816 ROOT.gSystem.Load(
'libDataQualityInterfaces')
817 ROOT.dqi.ConditionsSingleton.getInstance().setCondition(sys.argv[5])
821 if sys.argv[2] ==
"TEST":
822 configModule =
"TestDisplay"
823 elif sys.argv[2] ==
"RTT":
824 configModule =
"RTTDisplay"
825 elif sys.argv[2] ==
"TCT":
826 configModule =
"TCTDisplay"
827 elif sys.argv[2] ==
"FDR1":
828 configModule =
"fdr08_run1"
829 elif sys.argv[2] ==
"FDR2" or sys.argv[2] ==
"FDR2a" or sys.argv[2] ==
"FDR2b" or sys.argv[2] ==
"FDR2c":
830 configModule =
"fdr08_run2"
831 elif sys.argv[2] ==
"Cosmics08":
832 configModule =
"data08_cos"
833 elif sys.argv[2] ==
"SingleBeam08":
834 configModule =
"data08_1beam"
836 configModule = sys.argv[2]
841 print(
"Could not import configuration module \'" + configModule +
"\'")
845 config = cmod.dqconfig
847 print(
"Configuration object 'dqconfig' not defined in module \'" + configModule +
"\'")