#!/usr/bin/env python # # Ported to GlueX by Sean Dobbs (s-dobbs@northwestern.edu), 2014 # # Copyright 2004 Cornell University, Ithaca, NY 14853. All rights reserved. # # Author: Valentin Kuznetsov, 2004 """ EventStore builder supports SQLite/MySQL DBs through sqlite and MySQLdb modules, respectively. All available options are declare below and can be viewed by using -help option. It keep track of users command through esdb.history file Log of all SQL queries are saved into esdb.log Compensation SQL queries can be found in esdb.compensate_YYYYMMDD_HHMMSS_PID """ import os, sys, string, time, glob, stat import ESManager, os_path_util, es_init, sql_util, gen_util, esdb_auth from es_init import ESInit, checkArg def ESBuilder(args): """ESBuilder is a main injection tool. It supports two types of DBs: MySQL and SQLite. The injection can be done for variety of file formats: evio, hddm, idxa. For option information and usage please use '-help' option. For option description '--help'. For specific injection types please use '-examples' option. Please note, ESBuilder is a wrapper shell script around ESBuilder.py module which does the work. """ localOpt =["[ -add ]"] localOpt.append("[ -grade ] [ -time ]") localOpt.append("[ -dataVersionName ] [ -view ]") localOpt.append("[ -listOfParents ]") localOpt.append("[ -output ] [ -HSMDir ]") localOpt.append("[ -dupRead ] [ -skim ] [ -no-skim ]") localOpt.append("[ -masterDB ]") usage=es_init.helpMsg("ESBuilder",localOpt) usageDescription=""" Option description: * -grade: specifies the grade, e.g. "physics", "p2-unchecked" * -add: adds data file(s) to the EventStore You may specify: directory, file name or a list of files For patterns use '*', e.g MC*tau*.pds * -output: output location for storing key/location files * -dataVersionName: specifies the data version name (aka svName) -time: specifies the timeStamp, e.g. 20090227. If time is not provided will try to append to existing grade/dataVersionName or use a one day in a future as new timeStamp if no grade/dataVersionName combination is found. -view: specifies the view, e.g. "tau" -listOfParents specifies list of parents for given injection, e.g. while injecting p2-unchecked grade its parent is 'daq'. -newDB: force the creation of a new EventStore -sqlite use the SQLite version of EventStore default sqlite.db, otherwise a fileName needs to be provided -mysql use the MySQL version of EventStore. In order to access MySQL you need either provide login/password through the -user/-password options or create $HOME/.esdb.conf with user:password entry -masterDB specifies host and db name of the master you want to use -verbose: verbose mode, a lot of useful printout -idleMode when this flag is specified, no key/location file will be generated (useful once you have them and want reproduce DB content). But content of DB will be updated. USE WITH CAUTION. -delete delete a grade from EventStore. USE WITH CAUTION. You need to provide the grade and the timeStamp. -HSMDir specifies output HSM directory. -logFile specifies the log file name. You may either provide a full file name (including path) or 'stdout' or 'stderr' to redirect your log to appropriate I/O stream. During injection an intermidiate files esdb.log.YYYYMMDD_HHMMSS_PID will be created. Once a job successfully finishes, the esdb.log.YYYYMMDD_HHMMSS_PID is moved to your logFile, otherwise esdb.log.YYYYMMDD_HHMMSS_PID remains. -profile perform internal profiling. -dupRead in the case of duplicated records force to use this source -skim force ESBuilder to use input files as a skim, i.e. find their parents and build combined location file for all of them -no-skim force ESBuilder to use input files as is Please note: required parameters are marked with (*). All options can be specified in any order. By default: view='all', EventStoreTMP DB is used and key/location files are generated. """ examples = es_init.ESExamples() userCommand="ESBuilder.py" optList, dictOpt = es_init.ESOptions(userCommand,args,usage,usageDescription) dbName,dbHost,userName,userPass,dbPort,dbSocket = optList[0] historyFile,logFile,verbose,profile = optList[1] userCommand = optList[2] # default values grade = "" timeS = gen_util.dayAhead() oDir = "" view = "all" run = 0 file = "" newDB = 0 delete = 0 genMode = 1 minRun = 0 maxRun = 1000000 localtime = time.strftime("%Y%m%d_%H%M%S",time.localtime()) uname = os.uname() svName = "" tempLogFile = "esdb.log.%s_%s"%(localtime,os.getpid()) fileList = [] listOfParents = [] oHSMDir = "" dupRead = "" skim = 0 noskim = 0 masterDBName = dbName masterDBHost = dbHost master = "" masterDB = "" masterDBPort = dbPort masterDBSocket= dbSocket # parse the rest of the options and form user's command x = 1 doNotRead = 0 while x < len(args): try: if args[x] == "-newDB": newDB = 1 x+=1 continue if args[x] == "-HSMDir": oHSMDir = args[x+1] checkArg([oHSMDir]) x+=2 continue if args[x] == "-dupRead": dupRead = args[x+1] checkArg([dupRead]) x+=2 continue if args[x] == "-dataVersionName": svName = args[x+1] checkArg([svName]) x+=2 continue if args[x] == "-grade": grade = args[x+1] checkArg([grade]) x+=2 continue if args[x] == "-time": timeS = args[x+1] checkArg([timeS]) x+=2 continue if args[x] == "-output": oDir = args[x+1]+"/" checkArg([oDir]) x+=2 continue if args[x] == "-runRange": minRun=int(args[x+1]) maxRun=int(args[x+2]) checkArg([minRun,maxRun]) x+=3 continue if args[x] == "-listOfParents": x+=1 while(args[x][0]!="-"): newArg = args[x] listOfParents.append(args[x]) x+=1 if len(args)==x: break checkArg(listOfParents) continue if args[x] == "-add": file = os_path_util.formAbsolutePath(args[x+1]) # first check if pattern is present if len(args)>x+2 and args[x+2][0]!="-": counter=0 for idx in xrange(x+1,len(args)): newArg = args[idx] if newArg[0]=="-": break counter+=1 if os.path.isfile(newArg): fileList.append(os_path_util.formAbsolutePath(newArg)) x+=counter+1 continue elif os.path.isdir(file): dir = file+"/" for f in os.listdir(dir): if string.split(f,".")[-1]!="pds": continue fileName=dir+f fileList.append(os_path_util.formAbsolutePath(fileName)) x+=2 continue elif os_path_util.isFile(file): if file[-5:]==".list": tmpList = open(file).readlines() for item in tmpList: fileList.append(string.split(item)[0]) else: fileList = [file] x+=2 continue # check if this file exists else: print "ESBuilder: no such file",file raise checkArg(fileList) if args[x] == "-view": view = args[x+1] checkArg([view]) x+=2 continue if args[x] == "-idleMode": genMode= 0 x+=1 continue if args[x] == "-skim": skim= 1 x+=1 continue if args[x] == "-no-skim": noskim= 1 x+=1 continue if args[x] == "-masterDB": masterDB = args[x+1] master = 1 checkArg([masterDB]) x+=2 continue # if we reach here, that means we found unkown option if dictOpt.has_key(args[x]): x+=dictOpt[args[x]] else: print "Option '%s' is not allowed"%args[x] raise except: sys.exit(1) ### AUTHENTICATION??? # check that USER=pass2, otherwise exit authUsers = ['gluex','sdobbs'] ### CHECK # check if USER environment is set up, otherwise use LOGNAME env = os.environ if not env.has_key('USER'): os.environ['USER']=env['LOGNAME'] if not authUsers.count(os.environ["USER"]) and dbName=="EventStore" and string.find(dbHost,'hallddb')!=-1: print "ERROR: Injection to db='EventStore' should be done from official (gluex) account for %s DB\n"%dbName print "For your own injection please use another db name" sys.exit(1) # check underlying OS, so far we only allow to inject from SunOS #if os.environ["USER"]=="pass2" and uname[0]!="SunOS": # print "ERROR: for pass2 account the EventStore injection should be done from SunOS\n" # sys.exit(1) ####################################### # form normalized abosulte paths oDir=os_path_util.formAbsolutePath(oDir) # check required parameters if not len(grade): print "ESBuilder requires to specify a grade, see -grade option" sys.exit(1) if string.find(grade,"unchecked")==-1 and view=="all": ### CHECK print "ESBuilder only allow to inject 'unchecked' grades" print " daq-unechecked, p2-unchecked, physics-unchecked" print "Either specify different view or inject as unchecked grade" print "Given grade='%s' view='%s'"%(grade,view) sys.exit(1) if not len(fileList): print "ESBuilder requires to specify input file(s) with -add option" sys.exit(1) # check permissions and access to output dir if not os.path.isdir(oDir): print "Output directory '%s' doesn't exists"%oDir print "ESBuilder requires to specify output dir to store key/location files, see -output option" sys.exit(1) if oDir and not os_path_util.checkPermission(oDir): print "You don't have permission to write to output area '%s'"%oDir sys.exit(1) # check permission to write to HSM if oHSMDir and not os.path.isdir(oHSMDir): print "HSM directory '%s' does not exists"%oHSMDir sys.exit(1) if not os_path_util.checkPermission(oHSMDir): print "You don't have permission to write to HSM location '%s'"%oHSMDir sys.exit(1) # check that all inputs are in place for file in fileList: if not os.path.isfile(file): print "File '%s' does not exists"%file sys.exit(1) if dupRead and not os.path.isfile(dupRead): print "File '%s' does not exists"%dupRead sys.exit(1) # connect to MySQL EventStoreDB outputLog, globalLog = es_init.ESOutputLog(logFile) db, dbType = es_init.ESDBConnector(dbHost,dbName,userName,userPass,'',dbPort,dbSocket) es_init.ESInput(userCommand,outputLog,dbType) # Be verbose dbinfo="\t grade\t'%s'\n\t timeStamp\t'%s'\n\t view\t\t'%s'\n"%(grade,timeS,view) if newDB: if verbose: print "Creating new tables DB:" print dbinfo else: if verbose: print "Updating existing tables in DB:" print dbinfo if genMode==0 and verbose: print "\n\t ===> Process running in Idle mode" # create instance of ESManager class mydb = ESManager.ESManager(db,dbType,outputLog) # set-up all parameters mydb.setOutputDir(oDir) mydb.setGenerateDB(newDB) mydb.setSVName(svName) mydb.setParents(listOfParents) mydb.setGrade(grade) mydb.setTimeStamp(timeS) mydb.setView(view) mydb.setMinRun(minRun) mydb.setMaxRun(maxRun) mydb.setVerboseLevel(verbose) mydb.setReadDuplicatesSource(dupRead) mydb.setSkimFlag(skim) mydb.setNoSkimFlag(noskim) mydb.setDBHost(dbHost) mydb.setDBName(dbName) mydb.setDBPort(dbPort) mydb.setDBSocket(dbSocket) # interpret the master option if masterDB: dbComponents = string.split(masterDB,"@") if len(dbComponents)==2: masterDBName = dbComponents[0] newComponents= string.split(dbComponents[1],":") masterDBHost = newComponents[0] port = socket = "" if len(newComponents)==2: port = newComponents[1] elif len(newComponents)==3: socket= newComponents[2] # masterDBHost,port,socket=string.split(dbComponents[1],":") if port: masterDBPort = port if socket: masterDBSocket = socket else: masterDBHost = dbComponents[0] else: login,adminInfo,cMasterName,cMasterHost,cMasterPort,cMasterSocket=esdb_auth.readConfigFile() if cMasterHost: masterDBHost = cMasterHost masterDBName = cMasterName masterDBPort = cMasterPort masterDBSocket= cMasterSocket mydb.setMasterDB(masterDBName,masterDBHost,masterDBPort,masterDBSocket) # update DB using transaction if delete: status = mydb.deleteGrade(delGrade,delTime) else: # for anything else try: status = mydb.updateDB(genMode,fileList,oHSMDir) except: print "ERROR: fail to process:" for item in fileList: print item print "--------------- See traceback ----------------" raise # close connection to db mydb.commit() mydb.close() returnStatus = es_init.ESOutput(status,userCommand,historyFile,outputLog,globalLog) return returnStatus # # main # if __name__ == "__main__": if not es_init.checkPythonVersion("2.4"): print "To run ESBuilder you need to have 2.4 or higher version of python" sys.exit(1) if sys.argv.count('-profile') and es_init.checkPythonVersion("2.3"): # include python profiler only if python version greater then 2.3 import hotshot # Python profiler import hotshot.stats # profiler statistics print "Run ESBuilder/ESManager in profiler mode" profiler = hotshot.Profile("profile.dat") profiler.run("ESBuilder(sys.argv)") profiler.close() stats = hotshot.stats.load("profile.dat") stats.sort_stats('time', 'calls') stats.print_stats() else: status = ESBuilder(sys.argv) sys.exit(status)