8 Module defining utilities for ATLAS command line/python use of COOL
11 from __future__
import print_function
12 import sys,os,getopt,time,calendar
13 from PyCool
import cool
20 Translate simple connection string (no slash) to mycool.db with given
21 instance, all others left alone
24 return 'sqlite://X;schema=mycool.db;dbname='+conn
30 Open COOL database with given connection, or force open if not possible
31 Return COOL database object, or None if cannot be opened
32 Database is opened in update mode
34 dbSvc=cool.DatabaseSvcFactory.databaseService()
37 db=dbSvc.openDatabase(conn2,
False)
38 except Exception
as e:
40 print (
'Could not connect to',conn,
'try to create it')
42 db=dbSvc.createDatabase(conn2)
43 except Exception
as e:
45 print (
'Could not create the database - give up')
51 Open COOL database with given connection for reading
53 dbSvc=cool.DatabaseSvcFactory.databaseService()
56 db=dbSvc.openDatabase(conn2,
True)
57 except Exception
as e:
59 print (
'Could not connect to',conn)
63 def ensureFolder(db,folder,spec,desc,version=cool.FolderVersioning.SINGLE_VERSION):
65 Ensure folder exists, creating it if needed with given spec
66 Return COOL folder object
68 if (
not db.existsFolder(folder)):
69 print (
'Attempting to create',folder,
'with description',desc)
72 folderSpec = cool.FolderSpecification(version,spec)
73 db.createFolder(folder,folderSpec,desc,
True)
74 print (
'Folder created')
75 except Exception
as e:
77 print (
'Could not create folder',folder)
79 return db.getFolder(folder)
83 Return the correct folder description string for Athena IOVDbSVc access
84 runLumi=True or False for timestamp
85 datatype= { AthenaAttributeList | CondAttrListCollection }
88 desc=
'<timeStamp>run-lumi</timeStamp>'
90 desc=
'<timeStamp>time</timeStamp>'
94 if (datatype==
'CondAttrListCollection'):
96 tname=
'CondAttrListCollection'
97 elif (datatype==
'AthenaAttributeList'):
99 tname=
'AthenaAttributeList'
100 elif (datatype==
'CondAttrListVec'):
102 tname=
'CondAttrListVec'
104 desc+=
'<addrHeader><address_header service_type=\"'+
str(stype)+
'\" clid=\"'+
str(clid)+
'\" /></addrHeader><typeName>'+tname+
'</typeName>'
108 "Convert argument to time in seconds, treating as a literal or date"
114 ts=time.strptime(val+
'/UTC',
'%Y-%m-%d:%H:%M:%S/%Z')
115 return int(calendar.timegm(ts))
117 print (
"ERROR in time specification, use e.g. 2007-05-25:14:01:00")
121 "Convert the IOVkey (63 bit) to a string representing timestamp"
122 if (iovkey==cool.ValidityKeyMin):
123 return "ValidityKeyMin"
124 elif (iovkey==cool.ValidityKeyMax):
125 return "ValidityKeyMax"
127 stime=
int(iovkey/1000000000)
128 return time.asctime(time.gmtime(stime))+
" UTC"
131 """Obtain a connection to the database coolstr (e.g.
132 COOLONL_INDET/OFLP200) using Oracle servers only, bypassing SQLite files
133 and simulating the action of DBReplicaSvc to choose the correct one.
134 Returns None in case a connection cannot be established.
135 debug=True produces debug printout to show servers being tried"""
136 dbSvc=cool.DatabaseSvcFactory.databaseService()
140 splitname=connstr.split(
'/')
141 forceSQLite=
'ATLAS_COOL_FORCESQLITE' in os.environ
142 if (debug
and forceSQLite):
143 print (
"ATLAS_COOL_FORCESQLITE: Force consideration of SQLite replicas")
144 if (len(splitname)!=2
or readOnly
is False or forceSQLite):
146 db=dbSvc.openDatabase(connstr,readOnly)
147 except Exception
as e:
150 if (
not readOnly
and (
'attempt to write a readonly database' in e.__repr__())):
151 print (
"Writeable open failed - retry in readonly mode")
152 db=dbSvc.openDatabase(connstr,
True)
156 if (debug):
print (
"Trying to establish connection for %s from Oracle" % connstr)
161 if (debug):
print (serverlist)
164 while len(serverlist)>0:
165 server=serverlist.pop()
168 if (
'FRONTIER_SERVER' in os.environ):
169 connstr=
'frontier://ATLF/();schema=ATLAS_%s;dbname=%s' % (schema,dbinst)
173 elif server==
'atlas_dd':
continue
175 connstr=
'oracle://%s;schema=ATLAS_%s;dbname=%s' % (server,schema,dbinst)
176 if (debug):
print (
"Attempting to open %s" % connstr)
178 dbconn=dbSvc.openDatabase(connstr)
179 if (dbconn
is not None and dbconn.isOpen()):
180 if (debug):
print (
"Established connection to %s" % server)
182 if (debug):
print (
"Cannot connect to %s" % server)
184 if (debug):
print (
"Exception connecting to %s" % server)
186 print (
"All available replicas tried - giving up")
190 """Return list of Oracle database server names to try, mimicing action of
191 Athena DBReplicaSvc"""
193 if configfile
is None:
194 print (
"Cannot find dbreplica.config")
199 for line
in configfile.readlines():
201 if (epos>0
and line[0]!=
"#"):
202 domains=line[0:epos].
split()
204 if ((hostname[-len(dom):]==dom
and len(dom)>best)
or (best==0
and dom==
'default')):
206 serverlist=line[epos+1:].
split()
208 if (len(serverlist)==0):
209 print (
"No suitable servers found")
214 """Find the file leaf using the DATAPATH variable to look for it
215 Return a read-only file object, or None if not found.
216 If retFile is false, just return the pathname.
217 Current directory takes precendence if file is there"""
219 paths=os.environ[
'DATAPATH'].
split(
':')
226 os.stat(path+
'/'+leaf)
228 return open(path+
'/'+leaf,
'r')
236 "Get the hostname including domain name if possible"
237 if (
'ATLAS_CONDDB' in os.environ):
238 name=os.environ[
'ATLAS_CONDDB']
241 name=os.environ[
'HOSTNAME']
246 name=socket.getfqdn()
251 if (name.find(
'.')>=0
and name[-6:]!=
".local"):
254 if (name[-6:]==
".local"):
255 print (
"WARNING. Hostname is ",name,
" which does not define a domain. Consider setting $ATLAS_CONDDB to avoid this")
260 name=subprocess.check_output(
'hostname --fqdn').
decode(
'utf-8')
265 if (name.find(
'illegal')>-1
or name.find(
'unrecognized')>-1):
266 print (
"WARNING. hostname --fqdn returned the following:",name)
267 print (
"Consider setting $ATLAS_CONDDB to avoid this.")
274 print (
'AtlCoolLib tests')
277 print (
'Could not create test database')
279 spec=cool.RecordSpecification()
280 spec.extend(
'testString',cool.StorageType.String255)
281 folder=
ensureFolder(db,
'/TEST/TEST1',spec,
athenaDesc(
True,
'CondAttrListCollection'),cool.FolderVersioning.MULTI_VERSION)
283 print (
'Could not create test folder')
290 Class coolTool implements a base for python command-line tools to access
291 and set data in COOL folders
292 Incomplete baseclass implementation - clients must implement the following:
293 - setup(self,args) - set additional arguments
294 - usage(self) - print usage
295 - execute(self) - execute command
296 - procopts(self,opts) - (optional) - process additional command switches
298 def __init__(self,name,readonly,minarg,maxarg,longopts):
300 Initialise class and process command line options and switches
316 fullopts=longopts+[
'r=',
'rs=',
'ru=',
'l=',
'ls=',
'lu=',
'ts=',
'tu=',
'debug']
317 opts,args=getopt.getopt(sys.argv[1:],
'',fullopts)
318 except getopt.GetoptError
as e:
322 if len(args)<minarg
or len(args)>maxarg:
323 print (name,
'takes between',minarg,
'and',maxarg,
'non-optional parameters')
341 print (
'Usage:',self.
name,
' {<options>} dbname ',)
345 print (
'Options to specify IOV (default valid for all intervals)')
346 print (
'--rs=<first run>')
347 print (
'--ru=<last run> (inclusive)')
348 print (
'--r=<run> (only single run)')
349 print (
'--ls=<lumi block since>')
350 print (
'--l=<lumi block> (only single LB)')
351 print (
'--lu=<lumi block until> (inclusive)')
352 print (
'--ts=<initial timestamp> (in seconds)')
353 print (
'--tu=<final timestamp> (in seconds)')
354 print (
'--debug: Enable debugging information')
375 if (o==
'--debug'): self.
debug=
True
378 print (
'>== Data valid for run,LB [',self.
runmin,
',',self.
lumimin,
'] to [',self.
runmax,
',',self.
lumimax,
']')
387 print (
'ERROR in IOV definition: until<since')
396 """Hold a list of IOVs (start/end pairs) which are good, allowing parts
397 of list to be vetoed. start/end interpreted in COOL convention"""
399 "Initalise RangeList with given start and end (end=1 after last valid)"
404 "Veto part of the original range, splitting it if needed"
405 if (start>=end):
return
406 if (len(self.
_starts)==0):
return
417 elif (start<=self.
_ends[ix]
and end>=self.
_ends[ix]):
422 oldend=self.
_ends[ix]
429 """Return a list of tuples giving the allowed (start,end) within the
430 specified (start,end)"""
438 "Print representation of range as list of [x,y] allowed values"
445 "Remove the entry at idx"
450 "Put a new entry at idx, moving others to make space"
452 self.
_ends.insert(idx,end)
455 "Translation between timestamps and RunLB IOVs using /TRIGGER/LUMI/LBLB"
458 "Initialise and cache using the given DB connection, for RLB start/end"
469 lblbname=
'/TRIGGER/LUMI/LBLB'
471 readfolder=self.
readdb.getFolder(lblbname)
472 except Exception
as e:
474 print (
"Could not access folder %s " % lblbname)
475 raise RuntimeError (
"TimeStampToRLB initialisation error")
479 readobjs=readfolder.browseObjects(self.
since,self.
until,cool.ChannelSelection.all())
480 while readobjs.goToNext():
481 readobj=readobjs.currentRef()
482 payload=readobj.payload()
483 if (isFirst
is True):
487 self.
EndTime = payload[
'EndTime']
488 except Exception
as e:
490 print (
"Problem reading data from folder %s" % lblbname)
491 raise RuntimeError (
"TimeStampToRLB: initialisation error")
493 raise RuntimeError (
"TimeStampToRLB: no data for given runs")
496 lbtimename=
'/TRIGGER/LUMI/LBTIME'
498 readfolder=self.
readdb.getFolder(lbtimename)
499 except Exception
as e:
501 print (
"Problem accessing folder %s" % lbtimename)
502 raise RuntimeError (
"TimeStampToRLB: Initialisation error")
504 readobjs=readfolder.browseObjects(self.
StartTime, self.
EndTime, cool.ChannelSelection.all())
505 while readobjs.goToNext():
506 readobj=readobjs.currentRef()
507 payload=readobj.payload()
508 TimeStampStart = readobj.since()
509 TimeStampEnd = readobj.until()
510 iov=(payload[
'Run'] << 32)+payload[
'LumiBlock']
514 except Exception
as e:
516 print (
"Problem reading from folder %s" % lbtimename)
517 raise RuntimeError (
"TimeStampToRLB: Time data access error")
518 print (
"TimeStampToRLB initialised with %i entries in map" % len(self.
RLMap))
520 def getRLB(self,timestamp,StartType=True):
521 """Lookup a timestamp value. If it is outside a run, round up to next
522 run (StartType=True) or down to previous (StartType=False)"""
527 if (timestamp <= TSbegin):
534 if (timestamp >= TSend):
542 if __name__==
'__main__':