diff --git a/SAS/OTDB/CMakeLists.txt b/SAS/OTDB/CMakeLists.txt index 340a03b3ed585d35df9a91ad07f7bbb1f7a316c9..36bd8e2e438c871fb5609864c6890eecf89bad45 100644 --- a/SAS/OTDB/CMakeLists.txt +++ b/SAS/OTDB/CMakeLists.txt @@ -9,3 +9,5 @@ lofar_find_package(PQXX REQUIRED) add_subdirectory(include/OTDB) add_subdirectory(src) add_subdirectory(test) +add_subdirectory(bin) + diff --git a/SAS/OTDB/bin/CMakeLists.txt b/SAS/OTDB/bin/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..37030dc6bbd1024902e59b28ccd7e449aa1aac24 --- /dev/null +++ b/SAS/OTDB/bin/CMakeLists.txt @@ -0,0 +1,6 @@ +# $Id$ + +install (PROGRAMS + database.py + makeDefaultTemplates.py + DESTINATION sbin) diff --git a/SAS/OTDB/bin/database.py b/SAS/OTDB/bin/database.py new file mode 100644 index 0000000000000000000000000000000000000000..f6aa3ece6ace1e268dfde32bed62bca0be7c5ae2 --- /dev/null +++ b/SAS/OTDB/bin/database.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python +#coding: iso-8859-15 + +## database info +dbName="LOFAR_2" +dbHost="sas001" + +def getDBname(): + return(dbName) + +def getDBhost(): + return(dbHost) + diff --git a/SAS/OTDB/bin/makeDefaultTemplates.py b/SAS/OTDB/bin/makeDefaultTemplates.py new file mode 100755 index 0000000000000000000000000000000000000000..057f901633a0c1adc23637e40918a35decde789a --- /dev/null +++ b/SAS/OTDB/bin/makeDefaultTemplates.py @@ -0,0 +1,209 @@ +#!/usr/bin/env python +#coding: iso-8859-15 +import os,sys,time,pg +from database import * + +# get info from database.py +dbName=getDBname() +dbHost=getDBhost() + +# calling stored procedures only works from the pg module for some reason. +otdb = pg.connect(user="postgres", host=dbHost, dbname=dbName) + +# +# addIndexedComponent(treeID, keyName) +# +def addIndexedComponent(treeID, keyName): + """ + When parameter belongs to indexed node try to find parent unindexed component in the newtree + eg. keyName = ObsSW.Observation.Beam[5].angle1 + """ + parts = keyName.rsplit('.', 2) # [ObsSW.Observation , Beam[5], angle1 ] + if len(parts) == 3 and parts[1].endswith(']'): + nodeName = parts[0]+'.'+parts[1].rstrip('[]0123456789') # ObsSW.Observation.Beam + dupIndex = parts[1].rstrip(']').split('[')[1] # 5 + orgNodeID = otdb.query("select * from getVTitem(%s, '%s')" % (treeID, nodeName)).getresult()[0][0] + newNodeID = otdb.query("select * from dupVTnode(1, %s, %s, '%s')" % (treeID, orgNodeID, dupIndex)) + print " %s: %-75s added to the tree" % (treeID, parts[0]+'.'+parts[1]) + return newNodeID + +# +# createNewDefaultTemplate(orgTemplateID, newMasterTemplateID, orgTemplateInfo) +# +def createNewDefaultTemplate(orgTmplID, newMasterTmplID, orgTmplInfo): + """ + Create a new defaultTemplate based on the 'newMaster' information that has the changed values + of the original default template. + """ + # copy tree including description and template name + print "=> Reconstructing tree %s" % orgTmplID + newTmplID = otdb.query("select * from copyTree(1, %s)" % newMasterTmplID).getresult()[0][0] + print " copy has ID: %s" % newTmplID + otdb.query("select * from setDescription(1, %s, '%s')" % (newTmplID, orgTmplInfo['description'])) + otdb.query("select * from assignTemplateName(1, %s, '_new_ %s')" % (newTmplID, orgTmplInfo['treeName'])) + + # loop over all values that were changed in the old template + treeIdentification = "%s%d" % (orgTmplInfo['nodeName'], orgTmplInfo['version']) + for line in os.popen("comm -23 dfltTree%s MasterTree_%s" % (orgTmplID, treeIdentification)).read().splitlines(): + (key, value) = line.split('=',1) + # search same item in the new template + # (nodeid, parentid, paramdefid, name, index, leaf, instances, limits, description) + (nodeid, instances, limits) = \ + otdb.query("select nodeid,instances,limits from getVTitem(%s, '%s')" % (newTmplID, key)).getresult()[0] + + # if it doesn't exist, add it when it is a parameter from an indexed node + if nodeid == None: + try: + dummy = addIndexedComponent(newTmplID, key) + except: + print " %s: %-75s not in the new tree" % (newTmplID, key) + continue + else: + # no exception: try again to get the parameter in the new template + (nodeid, instances, limits) = \ + otdb.query("select nodeid,instances,limits from getVTitem(%s, '%s')" % (newTmplID, key)).getresult()[0] + + # update value if needed + if limits == value: + print " %s: %-75s value is equal" % (newTmplID, key) + else: + print " %s: %-75s %s --> %s" % (newTmplID, key, limits, value) + otdb.query("select * from updateVTnode(1, %s, %s, '%s', '%s')" % (newTmplID, nodeid, instances, value)) + + # get a list with the removed items + parentNodes = {} + command = """comm -13 dfltTree%s MasterTree_%s | cut -d'=' -f1 >diff1 ; + comm -23 dfltTree%s MasterTree_%s | cut -d'=' -f1 >diff2 ; + comm -23 diff1 diff2 ; rm diff1 diff2 + """ % (orgTmplID, treeIdentification, orgTmplID, treeIdentification) + # loop over the list: when the NODE(=parent) of this parameter was removed in the ORIGINAL default template + # remove the NODE in the new template otherwise remove the parameter only + for key in os.popen(command).read().splitlines(): + parentname = key.rsplit('.',1)[0] + oldparentid = otdb.query("select nodeid from getVTitem(%s, '%s')" % (orgTmplID, parentname)).getresult()[0][0] + if oldparentid == None: + # parent of parameter was removed from old template, safe to delete it in the new template too + nodeid = otdb.query("select nodeid from getVTitem(%s, '%s')" % (newTmplID, parentname)).getresult()[0][0] + if nodeid != None: + otdb.query ("select * from removeVTNode(1, %s, %s)" % (newTmplID, nodeid)) + print " %s: %-75s removed node deleted" % (newTmplID, parentname) + else: + # parent of parameter still exists in old template, remove parameter itself only + nodeid = otdb.query("select nodeid from getVTitem(%s, '%s')" % (newTmplID, key)).getresult()[0][0] + if nodeid != None: + # found item: delete it + otdb.query ("select * from removeVTleafNode(%s)" % nodeid) + print " %s: %-75s parameter deleted" % (newTmplID, key) + + +# +# createParsetFile(treeID, nodeID, fileName) +# +def createParsetFile(treeID, nodeID, fileName): + """ + Create a parset file with name fileName from tree treeID starting at nodeID. + """ + parset = otdb.query("select * from exportTree(%s, %s, %s)" % (1, treeID, nodeID)).getresult() + print " Creating parset %s" % fileName + file = open(fileName, 'w'); + file.write(parset[0][0]) + file.close() + + +# +# makeMasterTemplateTreeAndParset(treeIdent, topNodeID) : templateID +# +def makeMasterTemplateTreeAndParset(treeIdent, topNodeID): + """ + Create a template tree in OTDB and save its parset as a master template. + """ + templateID = otdb.query("select * from instanciateVTtree(1, %s, '4')" % topNodeID).getresult()[0][0] + otdb.query("select * from setDescription(1, %s, 'MasterTemplate %s')" % (templateID, treeIdent)) + # Create the corresponding parsetFile + nodeDefID = otdb.query("select * from getTopNode(%s)" % templateID).dictresult()[0] + createParsetFile(templateID, nodeDefID['nodeid'], "MasterTree_%s" % treeIdent) + return templateID + +# +# MAIN +# +if __name__ == '__main__': + """ + makeDefaultTemplates reconstructs ALL default templates in OTDB to match a new master-tree. + Each default templates is compared with the master tree it originates from and the difference are applied + to a copy of the new master tree. + """ + + # check syntax of invocation + # Expected syntax: makeDefaultTemplates componentversion + if (len(sys.argv) != 2): + print "Syntax: %s <versionnumber of new master components>" % sys.argv[0] + sys.exit(1) + newVersion = int(sys.argv[1]) + + # Check if a component LOFAR of this version exists + versions = [v[0] for v in otdb.query("select version from getVCnodeList('LOFAR', 0, false)").getresult()] + versions.sort() + if newVersion not in versions: + print "ERROR: There is no LOFAR component with version %s.\nAvailable versions: %s" % (newVersion, versions) + sys.exit(1) + + # Give user escape possibility + print "About to create new default templates in database %s on host %s. Starting in 5 seconds..." % (dbName, dbHost) + time.sleep(5) + + print "=> Collecting info about default templates..." + # built dictionary with componentID, nodeID, nodeName, version and treeName of the default templates like: + # {6171: (412, 2589, 'LOFAR', 40506, 'master template 4.5.6'), + # 6121: (203, 426, 'LOFAR', 40000, 'test template')} + dfltTmplInfo = {} + dfltTemplateIDs = otdb.query("select * from getDefaultTemplates()").dictresult() + for dfltTemplate in dfltTemplateIDs: + description = otdb.query("select description from getTreeInfo(%s, 'false')" % dfltTemplate['treeid']).getresult()[0][0] + nodeDefID = otdb.query("select * from getTopNode(%s)" % dfltTemplate['treeid']).dictresult()[0] + nodeInfo = otdb.query("select * from getVICnodedef(%s)" % nodeDefID['paramdefid']).dictresult() + dfltTmplInfo[dfltTemplate['treeid']] = \ + {'componentID' : nodeDefID['paramdefid'], \ + 'nodeID' : nodeDefID['nodeid'], \ + 'nodeName' : nodeDefID['name'], \ + 'version' : nodeInfo[0]['version'], \ + 'treeName' : dfltTemplate['name'], \ + 'description' : description} + print " DefaultTemplate %s starts at %s (version %d) : %s" % \ + (dfltTemplate['treeid'], nodeDefID['name'], nodeInfo[0]['version'], dfltTemplate['name']) + + # second step create temporarely parsetfiles from all DefaultTemplates + print "=> Creating temporarely parsetfiles from the DefaultTemplates..." + for treeID in dfltTmplInfo: + createParsetFile(treeID, dfltTmplInfo[treeID]['nodeID'], "dfltTree%s" % treeID) + + # create parsets from the masterTemplates (original template) + # Note: Since multiple defaultTemplates can have the same Master template remember the + # master template parsetfile in masterTmplInfo + print "=> Creating temporarely master templates in the OTDB and create parsetfiles from them" + newMasterID = 0 + masterTmplInfo = {} + for dfltTmpl in dfltTmplInfo.values(): + treeIdentification = "%s%d" % (dfltTmpl['nodeName'], dfltTmpl['version']) + # if we didn't constructed it before do so now + if not masterTmplInfo.has_key(treeIdentification): + masterTmplID = makeMasterTemplateTreeAndParset(treeIdentification, dfltTmpl['componentID']) + masterTmplInfo[treeIdentification] = masterTmplID + print " Master template '%s' version %s = %s" % (dfltTmpl['nodeName'], dfltTmpl['version'], masterTmplID) + # when this master template is the destination master remember its ID + if dfltTmpl['version'] == newVersion: + newMasterID = masterTmplID + + # did we create a template for the new tree-version already + if newMasterID == 0: + topComponent = otdb.query("select nodeid from getVCnodelist('LOFAR', %d, false)" % newVersion).getresult()[0] + newMasterID = makeMasterTemplateTreeAndParset("LOFAR%d" % newVersion, topComponent) + + # for each old default template make a new template + print " TreeID of new master template = %s" % newMasterID + print "=> Creating new default templates for version %d" % newVersion + for treeID in dfltTmplInfo: + createNewDefaultTemplate(treeID, newMasterID, dfltTmplInfo[treeID]) + + otdb.close() + sys.exit(0)