def updateCS( changeSet ): global vo, dry, ceBdiiDict changeList = list( changeSet ) changeList.sort() if dry: gLogger.notice( 'The following needed changes are detected:\n' ) else: gLogger.notice( 'We are about to make the following changes to CS:\n' ) for entry in changeList: gLogger.notice( "%s/%s %s -> %s" % entry ) if not dry: csAPI = CSAPI() csAPI.initialize() result = csAPI.downloadCSData() if not result['OK']: gLogger.error( 'Failed to initialize CSAPI object', result['Message'] ) DIRACExit( -1 ) for section, option, value, new_value in changeSet: if value == 'Unknown' or not value: csAPI.setOption( cfgPath( section, option ), new_value ) else: csAPI.modifyValue( cfgPath( section, option ), new_value ) yn = raw_input( 'Do you want to commit changes to CS ? [default yes] [yes|no]: ' ) if yn == '' or yn.lower().startswith( 'y' ): result = csAPI.commit() if not result['OK']: gLogger.error( "Error while commit to CS", result['Message'] ) else: gLogger.notice( "Successfully committed %d changes to CS" % len( changeSet ) )
def __setCSElementStatus(self, elementName, elementType, statusType, status): """ Sets on the CS the Elements status """ # DIRAC doesn't store the status of ComputingElements nor FTS in the CS, so here we can just do nothing if elementType in ('ComputingElement', 'FTS'): return S_OK() # If we are here it is because elementType is either 'StorageElement' or 'Catalog' statuses = self.rssConfig.getConfigStatusType(elementType) if statusType not in statuses: gLogger.error("%s is not a valid statusType" % statusType) return S_ERROR("%s is not a valid statusType: %s" % (statusType, statuses)) if elementType == 'StorageElement': cs_path = "/Resources/StorageElements" elif elementType == 'Catalog': cs_path = "/Resources/FileCatalogs" # FIXME: This a probably outdated location (new one is in /Operations/[]/Services/Catalogs) # but needs to be VO-aware statusType = 'Status' csAPI = CSAPI() csAPI.setOption("%s/%s/%s/%s" % (cs_path, elementName, elementType, statusType), status) res = csAPI.commitChanges() if not res['OK']: gLogger.warn('CS: %s' % res['Message']) return res
def __setCSStorageElementStatus( self, elementName, statusType, status ): """ Sets on the CS the StorageElements status """ statuses = self.rssConfig.getConfigStatusType( 'StorageElement' ) if not statusType in statuses: gLogger.error( "%s is not a valid statusType" % statusType ) return S_ERROR( "%s is not a valid statusType: %s" % ( statusType, statuses ) ) csAPI = CSAPI() cs_path = "/Resources/StorageElements" csAPI.setOption( "%s/%s/%s" % ( cs_path, elementName, statusType ), status ) res = csAPI.commitChanges() if not res[ 'OK' ]: gLogger.warn( 'CS: %s' % res[ 'Message' ] ) return res
# FileManager = FileManagerPS # SecurityManager = FullSecurityManager # } # } # Databases # { # FileCatalogDB # { # DBName = FileCatalogDB # } # } # } # } from DIRAC.ConfigurationSystem.Client.CSAPI import CSAPI csAPI = CSAPI() for sct in ['Systems/DataManagement/Production/Services', 'Systems/DataManagement/Production/Services/FileCatalog' ]: res = csAPI.createSection( sct ) if not res['OK']: print res['Message'] exit( 1 ) csAPI.setOption( 'Systems/DataManagement/Production/Services/FileCatalog/DirectoryManager', 'DirectoryClosure' ) csAPI.setOption( 'Systems/DataManagement/Production/Services/FileCatalog/FileManager', 'FileManagerPs' ) csAPI.setOption( 'Systems/DataManagement/Production/Services/FileCatalog/SecurityManager', 'DirectorySecurityManagerWithDelete' ) csAPI.setOption( 'Systems/DataManagement/Production/Services/FileCatalog/UniqueGUID', True ) csAPI.commit()
Script.parseCommandLine() args = Script.getPositionalArgs() setupName = args[0] # Where to store outputs if not os.path.isdir('%s/sandboxes' % setupName): os.makedirs('%s/sandboxes' % setupName) # now updating the CS from DIRAC.ConfigurationSystem.Client.CSAPI import CSAPI csAPI = CSAPI() csAPI.setOption('Systems/WorkloadManagement/Production/Services/SandboxStore/BasePath', '%s/sandboxes' % setupName) csAPI.setOption('Systems/WorkloadManagement/Production/Services/SandboxStore/LogLevel', 'DEBUG') # Now setting a SandboxSE as the following: # ProductionSandboxSE # { # BackendType = DISET # AccessProtocol = dips # DIP # { # Host = localhost # Port = 9196 # ProtocolName = DIP # Protocol = dips # Path = /scratch/workspace/%s/sandboxes % setupName # Access = remote
class CE2CSAgent(AgentModule): addressTo = '' addressFrom = '' voName = '' subject = "CE2CSAgent" alternativeBDIIs = [] def initialize(self): # TODO: Have no default and if no mail is found then use the diracAdmin group # and resolve all associated mail addresses. self.addressTo = self.am_getOption('MailTo', self.addressTo) self.addressFrom = self.am_getOption('MailFrom', self.addressFrom) # create a list of alternative bdii urls self.alternativeBDIIs = self.am_getOption('AlternativeBDIIs', []) # check if the bdii url is appended by a port number, if not append the default 2170 for index, url in enumerate(self.alternativeBDIIs): if not url.split(':')[-1].isdigit(): self.alternativeBDIIs[index] += ':2170' if self.addressTo and self.addressFrom: self.log.info("MailTo", self.addressTo) self.log.info("MailFrom", self.addressFrom) if self.alternativeBDIIs: self.log.info("AlternativeBDII URLs:", self.alternativeBDIIs) self.subject = "CE2CSAgent" # This sets the Default Proxy to used as that defined under # /Operations/Shifter/SAMManager # the shifterProxy option in the Configuration can be used to change this default. self.am_setOption('shifterProxy', 'SAMManager') self.voName = self.am_getOption('VirtualOrganization', self.voName) if not self.voName: self.voName = getVO() if not self.voName: self.log.fatal("VO option not defined for agent") return S_ERROR() self.csAPI = CSAPI() return self.csAPI.initialize() def execute(self): self.log.info("Start Execution") result = getProxyInfo() if not result['OK']: return result infoDict = result['Value'] self.log.info(formatProxyInfoAsString(infoDict)) #Get a "fresh" copy of the CS data result = self.csAPI.downloadCSData() if not result['OK']: self.log.warn("Could not download a fresh copy of the CS data", result['Message']) self.__lookForCE() self.__infoFromCE() self.log.info("End Execution") return S_OK() def __checkAlternativeBDIISite(self, fun, *args): if self.alternativeBDIIs: self.log.warn("Trying to use alternative bdii sites") for site in self.alternativeBDIIs: self.log.info("Trying to contact alternative bdii ", site) if len(args) == 1: result = fun(args[0], host=site) elif len(args) == 2: result = fun(args[0], vo=args[1], host=site) if not result['OK']: self.log.error("Problem contacting alternative bddii", result['Message']) elif result['OK']: return result self.log.warn("Also checking alternative BDII sites failed") return result def __lookForCE(self): knownces = self.am_getOption('BannedCEs', []) resources = Resources(self.voName) result = resources.getEligibleResources('Computing', {'CEType': ['LCG', 'CREAM']}) if not result['OK']: return result siteDict = result['Value'] for site in siteDict: knownces += siteDict[site] # result = gConfig.getSections( '/Resources/Sites' ) # if not result['OK']: # return # grids = result['Value'] # # for grid in grids: # # result = gConfig.getSections( '/Resources/Sites/%s' % grid ) # if not result['OK']: # return # sites = result['Value'] # # for site in sites: # opt = gConfig.getOptionsDict( '/Resources/Sites/%s/%s' % ( grid, site ) )['Value'] # ces = List.fromChar( opt.get( 'CE', '' ) ) # knownces += ces response = ldapCEState('', vo=self.voName) if not response['OK']: self.log.error("Error during BDII request", response['Message']) response = self.__checkAlternativeBDIISite(ldapCEState, '', self.voName) return response newces = {} for queue in response['Value']: try: queuename = queue['GlueCEUniqueID'] except: continue cename = queuename.split(":")[0] if not cename in knownces: newces[cename] = None self.log.debug("newce", cename) body = "" possibleNewSites = [] for ce in newces.iterkeys(): response = ldapCluster(ce) if not response['OK']: self.log.warn("Error during BDII request", response['Message']) response = self.__checkAlternativeBDIISite(ldapCluster, ce) continue clusters = response['Value'] if len(clusters) != 1: self.log.warn("Error in cluster length", " CE %s Length %d" % (ce, len(clusters))) if len(clusters) == 0: continue cluster = clusters[0] fkey = cluster.get('GlueForeignKey', []) if type(fkey) == type(''): fkey = [fkey] nameBDII = None for entry in fkey: if entry.count('GlueSiteUniqueID'): nameBDII = entry.split('=')[1] break if not nameBDII: continue cestring = "CE: %s, GOCDB Name: %s" % (ce, nameBDII) self.log.info(cestring) response = ldapCE(ce) if not response['OK']: self.log.warn("Error during BDII request", response['Message']) response = self.__checkAlternativeBDIISite(ldapCE, ce) continue ceinfos = response['Value'] if len(ceinfos): ceinfo = ceinfos[0] systemName = ceinfo.get('GlueHostOperatingSystemName', 'Unknown') systemVersion = ceinfo.get('GlueHostOperatingSystemVersion', 'Unknown') systemRelease = ceinfo.get('GlueHostOperatingSystemRelease', 'Unknown') else: systemName = "Unknown" systemVersion = "Unknown" systemRelease = "Unknown" osstring = "SystemName: %s, SystemVersion: %s, SystemRelease: %s" % ( systemName, systemVersion, systemRelease) self.log.info(osstring) response = ldapCEState(ce, vo=self.voName) if not response['OK']: self.log.warn("Error during BDII request", response['Message']) response = self.__checkAlternativeBDIISite( ldapCEState, ce, self.voName) continue newcestring = "\n\n%s\n%s" % (cestring, osstring) usefull = False cestates = response['Value'] for cestate in cestates: queuename = cestate.get('GlueCEUniqueID', 'UnknownName') queuestatus = cestate.get('GlueCEStateStatus', 'UnknownStatus') queuestring = "%s %s" % (queuename, queuestatus) self.log.info(queuestring) newcestring += "\n%s" % queuestring if queuestatus.count('Production'): usefull = True if usefull: body += newcestring possibleNewSites.append( 'dirac-admin-add-site DIRACSiteName %s %s' % (nameBDII, ce)) if body: body = "We are glade to inform You about new CE(s) possibly suitable for %s:\n" % self.voName + body body += "\n\nTo suppress information about CE add its name to BannedCEs list." for possibleNewSite in possibleNewSites: body = "%s\n%s" % (body, possibleNewSite) self.log.info(body) if self.addressTo and self.addressFrom: notification = NotificationClient() result = notification.sendMail(self.addressTo, self.subject, body, self.addressFrom, localAttempt=False) return S_OK() def __infoFromCE(self): sitesSection = cfgPath('Resources', 'Sites') result = gConfig.getSections(sitesSection) if not result['OK']: return grids = result['Value'] changed = False body = "" for grid in grids: gridSection = cfgPath(sitesSection, grid) result = gConfig.getSections(gridSection) if not result['OK']: return sites = result['Value'] for site in sites: # if site[-2:]!='ru': # continue siteSection = cfgPath(gridSection, site) opt = gConfig.getOptionsDict(siteSection)['Value'] name = opt.get('Name', '') if name: coor = opt.get('Coordinates', 'Unknown') mail = opt.get('Mail', 'Unknown') result = ldapSite(name) if not result['OK']: self.log.warn("BDII site %s: %s" % (name, result['Message'])) result = self.__checkAlternativeBDIISite( ldapSite, name) if result['OK']: bdiisites = result['Value'] if len(bdiisites) == 0: self.log.warn(name, "Error in bdii: leng = 0") else: if not len(bdiisites) == 1: self.log.warn( name, "Warning in bdii: leng = %d" % len(bdiisites)) bdiisite = bdiisites[0] try: longitude = bdiisite['GlueSiteLongitude'] latitude = bdiisite['GlueSiteLatitude'] newcoor = "%s:%s" % (longitude, latitude) except: self.log.warn("Error in bdii coor") newcoor = "Unknown" try: newmail = bdiisite[ 'GlueSiteSysAdminContact'].split( ":")[-1].strip() except: self.log.warn("Error in bdii mail") newmail = "Unknown" self.log.debug("%s %s %s" % (name, newcoor, newmail)) if newcoor != coor: self.log.info("%s" % (name), "%s -> %s" % (coor, newcoor)) if coor == 'Unknown': self.csAPI.setOption( cfgPath(siteSection, 'Coordinates'), newcoor) else: self.csAPI.modifyValue( cfgPath(siteSection, 'Coordinates'), newcoor) changed = True if newmail != mail: self.log.info("%s" % (name), "%s -> %s" % (mail, newmail)) if mail == 'Unknown': self.csAPI.setOption( cfgPath(siteSection, 'Mail'), newmail) else: self.csAPI.modifyValue( cfgPath(siteSection, 'Mail'), newmail) changed = True celist = List.fromChar(opt.get('CE', '')) if not celist: self.log.warn(site, 'Empty site list') continue # result = gConfig.getSections( cfgPath( siteSection,'CEs' ) # if not result['OK']: # self.log.debug( "Section CEs:", result['Message'] ) for ce in celist: ceSection = cfgPath(siteSection, 'CEs', ce) result = gConfig.getOptionsDict(ceSection) if not result['OK']: self.log.debug("Section CE", result['Message']) wnTmpDir = 'Unknown' arch = 'Unknown' os = 'Unknown' si00 = 'Unknown' pilot = 'Unknown' cetype = 'Unknown' else: ceopt = result['Value'] wnTmpDir = ceopt.get('wnTmpDir', 'Unknown') arch = ceopt.get('architecture', 'Unknown') os = ceopt.get('OS', 'Unknown') si00 = ceopt.get('SI00', 'Unknown') pilot = ceopt.get('Pilot', 'Unknown') cetype = ceopt.get('CEType', 'Unknown') result = ldapCE(ce) if not result['OK']: self.log.warn('Error in bdii for %s' % ce, result['Message']) result = self.__checkAlternativeBDIISite(ldapCE, ce) continue try: bdiice = result['Value'][0] except: self.log.warn('Error in bdii for %s' % ce, result) bdiice = None if bdiice: try: newwnTmpDir = bdiice['GlueSubClusterWNTmpDir'] except: newwnTmpDir = 'Unknown' if wnTmpDir != newwnTmpDir and newwnTmpDir != 'Unknown': section = cfgPath(ceSection, 'wnTmpDir') self.log.info(section, " -> ".join( (wnTmpDir, newwnTmpDir))) if wnTmpDir == 'Unknown': self.csAPI.setOption(section, newwnTmpDir) else: self.csAPI.modifyValue(section, newwnTmpDir) changed = True try: newarch = bdiice[ 'GlueHostArchitecturePlatformType'] except: newarch = 'Unknown' if arch != newarch and newarch != 'Unknown': section = cfgPath(ceSection, 'architecture') self.log.info(section, " -> ".join( (arch, newarch))) if arch == 'Unknown': self.csAPI.setOption(section, newarch) else: self.csAPI.modifyValue(section, newarch) changed = True try: newos = '_'.join( (bdiice['GlueHostOperatingSystemName'], bdiice['GlueHostOperatingSystemVersion'], bdiice['GlueHostOperatingSystemRelease'])) except: newos = 'Unknown' if os != newos and newos != 'Unknown': section = cfgPath(ceSection, 'OS') self.log.info(section, " -> ".join((os, newos))) if os == 'Unknown': self.csAPI.setOption(section, newos) else: self.csAPI.modifyValue(section, newos) changed = True body = body + "OS was changed %s -> %s for %s at %s\n" % ( os, newos, ce, site) try: newsi00 = bdiice['GlueHostBenchmarkSI00'] except: newsi00 = 'Unknown' if si00 != newsi00 and newsi00 != 'Unknown': section = cfgPath(ceSection, 'SI00') self.log.info(section, " -> ".join( (si00, newsi00))) if si00 == 'Unknown': self.csAPI.setOption(section, newsi00) else: self.csAPI.modifyValue(section, newsi00) changed = True try: rte = bdiice[ 'GlueHostApplicationSoftwareRunTimeEnvironment'] if self.voName.lower() == 'lhcb': if 'VO-lhcb-pilot' in rte: newpilot = 'True' else: newpilot = 'False' else: newpilot = 'Unknown' except: newpilot = 'Unknown' if pilot != newpilot and newpilot != 'Unknown': section = cfgPath(ceSection, 'Pilot') self.log.info(section, " -> ".join( (pilot, newpilot))) if pilot == 'Unknown': self.csAPI.setOption(section, newpilot) else: self.csAPI.modifyValue(section, newpilot) changed = True result = ldapService(ce) if not result['OK']: result = self.__checkAlternativeBDIISite( ldapService, ce) if result['OK'] and result['Value']: services = result['Value'] newcetype = 'LCG' for service in services: if service['GlueServiceType'].count('CREAM'): newcetype = "CREAM" else: newcetype = 'Unknown' if cetype != newcetype and newcetype != 'Unknown': section = cfgPath(ceSection, 'CEType') self.log.info(section, " -> ".join( (cetype, newcetype))) if cetype == 'Unknown': self.csAPI.setOption(section, newcetype) else: self.csAPI.modifyValue(section, newcetype) changed = True result = ldapCEState(ce, vo=self.voName) #getBDIICEVOView if not result['OK']: self.log.warn('Error in bdii for queue %s' % ce, result['Message']) result = self.__checkAlternativeBDIISite( ldapCEState, ce, self.voName) continue try: queues = result['Value'] except: self.log.warn('Error in bdii for queue %s' % ce, result['Massage']) continue for queue in queues: try: queueName = queue['GlueCEUniqueID'].split('/')[-1] except: self.log.warn('error in queuename ', queue) continue try: newmaxCPUTime = queue['GlueCEPolicyMaxCPUTime'] except: newmaxCPUTime = None newsi00 = None try: caps = queue['GlueCECapability'] if type(caps) == type(''): caps = [caps] for cap in caps: if cap.count('CPUScalingReferenceSI00'): newsi00 = cap.split('=')[-1] except: newsi00 = None queueSection = cfgPath(ceSection, 'Queues', queueName) result = gConfig.getOptionsDict(queueSection) if not result['OK']: self.log.warn("Section Queues", result['Message']) maxCPUTime = 'Unknown' si00 = 'Unknown' else: queueopt = result['Value'] maxCPUTime = queueopt.get('maxCPUTime', 'Unknown') si00 = queueopt.get('SI00', 'Unknown') if newmaxCPUTime and (maxCPUTime != newmaxCPUTime): section = cfgPath(queueSection, 'maxCPUTime') self.log.info( section, " -> ".join( (maxCPUTime, newmaxCPUTime))) if maxCPUTime == 'Unknown': self.csAPI.setOption(section, newmaxCPUTime) else: self.csAPI.modifyValue(section, newmaxCPUTime) changed = True if newsi00 and (si00 != newsi00): section = cfgPath(queueSection, 'SI00') self.log.info(section, " -> ".join( (si00, newsi00))) if si00 == 'Unknown': self.csAPI.setOption(section, newsi00) else: self.csAPI.modifyValue(section, newsi00) changed = True if changed: self.log.info(body) if body and self.addressTo and self.addressFrom: notification = NotificationClient() result = notification.sendMail(self.addressTo, self.subject, body, self.addressFrom, localAttempt=False) return self.csAPI.commit() else: self.log.info("No changes found") return S_OK()
if not ses: gLogger.error( "There were no SEs provided" ) DIRAC.exit() readAllowed = [] writeAllowed = [] checkAllowed = [] storageCFGBase = "/Resources/StorageElements" for se in ses: res = gConfig.getOptionsDict( "%s/%s" % ( storageCFGBase, se ) ) if not res['OK']: gLogger.error( "Storage Element %s does not exist" % se ) continue existingOptions = res['Value'] if read and existingOptions['ReadAccess'] == "InActive": res = csAPI.setOption( "%s/%s/ReadAccess" % ( storageCFGBase, se ), "Active" ) if not res['OK']: gLogger.error( "Failed to update %s read access to Active" % se ) else: gLogger.debug( "Successfully updated %s read access to Active" % se ) readAllowed.append( se ) if write and existingOptions['WriteAccess'] == "InActive": res = csAPI.setOption( "%s/%s/WriteAccess" % ( storageCFGBase, se ), "Active" ) if not res['OK']: gLogger.error( "Failed to update %s write access to Active" % se ) else: gLogger.debug( "Successfully updated %s write access to Active" % se ) writeAllowed.append( se ) if check and existingOptions['CheckAccess'] == "InActive": res = csAPI.setOption( "%s/%s/CheckAccess" % ( storageCFGBase, se ), "Active" ) if not res['OK']:
res = getProxyInfo() if not res['OK']: gLogger.error( "Failed to get proxy information", res['Message'] ) DIRAC.exit( 2 ) userName = res['Value']['username'] group = res['Value']['group'] catalogCFGBase = "/Resources/FileCatalogs/LcgFileCatalogCombined" banned = [] for site in sites: res = gConfig.getOptionsDict( '%s/%s' % ( catalogCFGBase, site ) ) if not res['OK']: gLogger.error( "The provided site (%s) does not have an associated catalog." % site ) continue res = csAPI.setOption( "%s/%s/Status" % ( catalogCFGBase, site ), "InActive" ) if not res['OK']: gLogger.error( "Failed to update %s catalog status to InActive" % site ) else: gLogger.debug( "Successfully updated %s catalog status to InActive" % site ) banned.append( site ) if not banned: gLogger.error( "Failed to ban any catalog mirrors" ) DIRAC.exit( -1 ) res = csAPI.commitChanges() if not res['OK']: gLogger.error( "Failed to commit changes to CS", res['Message'] ) DIRAC.exit( -1 )
class DDSimTarMaker( object ): """ create a tarball of the DDSim release """ def __init__( self ): self.detmodels = {} self.lcgeo_env="lcgeo_DIR" self.ddhep_env="DD4HEP" self.softSec = "/Operations/Defaults/AvailableTarBalls" self.version = '' self.platform = 'x86_64-slc5-gcc43-opt' self.comment = "" self.name = "ddsim" self.csapi = None self.tarBallName = None self.md5sum = None def copyDetectorModels( self, basePath, folder, targetFolder ): """copy the compact folders to the targetFolder """ for root,dirs,_files in os.walk( os.path.join(basePath, folder) ): for direct in dirs: if root.endswith("compact"): ## the main xml file must have the same name as the folder, ILD and CLIC follow this convention already xmlPath = os.path.join( root, direct, direct+".xml") if os.path.exists( xmlPath ): self.detmodels[direct] = "detectors/"+direct+"/"+direct+".xml" copyFolder( os.path.join(root, direct), targetFolder ) def createTarBall( self, folder ): """create a tar ball from the folder tar zcf $TARBALLNAME $LIBFOLDER/* """ ##Create the Tarball if os.path.exists(self.tarBallName): os.remove(self.tarBallName) gLogger.notice("Creating Tarball...") myappTar = tarfile.open(self.tarBallName, "w:gz") myappTar.add(folder, self.tarBallName[:-4]) myappTar.close() self.md5sum = md5.md5(open( self.tarBallName, 'r' ).read()).hexdigest() gLogger.notice("...Done") return S_OK( "Created Tarball") def parseArgs( self ): """ parse the command line arguments""" if len(sys.argv) != 3: raise RuntimeError( "Wrong number of arguments in call: '%s'" % " ".join(sys.argv) ) self.name = sys.argv[1] self.version = sys.argv[2] self.tarBallName = "%s%s.tgz" % (self.name, self.version) def checkEnvironment( self ): """ check if dd4hep and lcgeo are in the environment """ for var in [ self.ddhep_env, self.lcgeo_env , 'ROOTSYS' ]: if var not in os.environ: raise RuntimeError( "%s is not set" % var ) return os.environ[self.ddhep_env], os.environ[self.lcgeo_env], os.environ['ROOTSYS'] def createCSEntry( self ): """add the entries for this version into the Configuration System <version> { TarBall = ddsim<version>.tgz AdditionalEnvVar { ROOTSYS = /cvmfs/ilc.desy.de/sw/x86_64_gcc44_sl6/root/5.34.30 G4INSTALL = /cvmfs/ilc.desy.de/sw/x86_64_gcc44_sl6/geant4/10.01 G4DATA = /cvmfs/ilc.desy.de/sw/x86_64_gcc44_sl6/geant4/10.01/share/Geant4-10.1.0/data } Overwrite = True } Operations/DDSimDetectorModels/<Version> { CLIC_o2_v03 = detectors/CLIC_o2_v03/CLIC_o2_v03.xml ... } """ #FIXME: Get root and geant4 location from environment, make sure it is cvmfs csParameter = { "TarBall": self.tarBallName, "AdditionalEnvVar": { "ROOTSYS" : os.environ.get("ROOTSYS"), "G4INSTALL" : os.environ.get("G4INSTALL"), "G4DATA" : os.environ.get("G4DATA"), }, "Md5Sum": self.md5sum, } pars = dict( platform=self.platform, name="ddsim", version=self.version ) csPath = os.path.join( self.softSec , "%(platform)s/%(name)s/%(version)s/" % pars ) pprint(csParameter) result = self.insertCSSection( csPath, csParameter ) csPathModels = "Operations/Defaults/DDSimDetectorModels" csModels = { self.version : self.detmodels } pprint(csModels) result = self.insertCSSection( csPathModels, csModels ) if self.csapi is not None: resProxy = checkOrGetGroupProxy( "diracAdmin" ) if not resProxy['OK']: gLogger.error( "Failed to get AdminProxy", resProxy['Message'] ) raise RuntimeError( "Failed to get diracAdminProxy" ) self.csapi.commit() if not result['OK']: gLogger.error( "Failed to create CS Section", result['Message'] ) raise RuntimeError( "Failed to create CS Section" ) def insertCSSection( self, path, pardict ): """ insert a section and values (or subsections) into the CS :param str path: full path of the new section :param str pardict: dictionary of key values in the new section, values can also be dictionaries :return: S_OK(), S_ERROR() """ from DIRAC.ConfigurationSystem.Client.CSAPI import CSAPI if self.csapi is None: self.csapi = CSAPI() for key, value in pardict.iteritems(): newSectionPath = os.path.join(path,key) gLogger.debug( "Adding to cs %s : %s " % ( newSectionPath, value ) ) self.csapi.createSection( path ) if isinstance( value, dict ): res = self.insertCSSection( newSectionPath, value ) else: res = self.csapi.setOption( newSectionPath, value ) if not res['OK']: return res else: gLogger.notice( "Added to CS: %s " % res['Value'] ) return S_OK("Added all things to cs") def createDDSimTarBall( self ): """ do everything to create the DDSim tarball""" self.parseArgs() ddBase, lcgeoBase, _rootsys = self.checkEnvironment() realTargetFolder = os.path.join( os.getcwd(), self.name+self.version ) targetFolder = os.path.join( os.getcwd(), "temp", self.name+self.version ) for folder in (targetFolder, targetFolder+"/lib"): try: os.makedirs( folder ) except OSError: pass libraries = set() rootmaps = set() dd4hepLibPath = getLibraryPath( ddBase ) lcgeoPath = getLibraryPath( lcgeoBase ) self.copyDetectorModels( lcgeoBase, "CLIC" , targetFolder+"/detectors" ) self.copyDetectorModels( lcgeoBase, "ILD" , targetFolder+"/detectors" ) copyFolder( ddBase+"/DDDetectors/compact", realTargetFolder.rstrip("/")+"/DDDetectors") libraries.update( getFiles( dd4hepLibPath, ".so") ) libraries.update( getFiles( lcgeoPath, ".so" ) ) rootmaps.update( getFiles( dd4hepLibPath, ".rootmap") ) rootmaps.update( getFiles( lcgeoPath, ".rootmap" ) ) pprint( libraries ) pprint( rootmaps ) allLibs = set() for lib in libraries: allLibs.update( getDependentLibraries(lib) ) ### remote root and geant4 libraries, we pick them up from allLibs = set( [ lib for lib in allLibs if not ( "/geant4/" in lib.lower() or "/root/" in lib.lower()) ] ) print allLibs copyLibraries( libraries, targetFolder+"/lib" ) copyLibraries( allLibs, targetFolder+"/lib" ) copyLibraries( rootmaps, targetFolder+"/lib" ) getPythonStuff( ddBase+"/python" , targetFolder+"/lib/") getPythonStuff( lcgeoBase+"/lib/python", targetFolder+"/lib/" ) getPythonStuff( lcgeoBase+"/bin/ddsim", targetFolder+"/bin/" ) ##Should get this from CVMFS #getRootStuff( rootsys, targetFolder+"/ROOT" ) copyFolder( targetFolder+"/", realTargetFolder.rstrip("/") ) killRPath( realTargetFolder ) resolveLinks( realTargetFolder+"/lib" ) removeSystemLibraries( realTargetFolder+"/lib" ) #removeSystemLibraries( realTargetFolder+"/ROOT/lib" ) print self.detmodels self.createTarBall( realTargetFolder ) self.createCSEntry()
args = Script.getPositionalArgs() setupName = args[0] # Where to store outputs if not os.path.isdir("%s/sandboxes" % setupName): os.makedirs("%s/sandboxes" % setupName) # now updating the CS from DIRAC.ConfigurationSystem.Client.CSAPI import CSAPI csAPI = CSAPI() csAPI.setOption( "Systems/WorkloadManagement/Production/Services/SandboxStore/BasePath", "%s/sandboxes" % setupName) csAPI.setOption( "Systems/WorkloadManagement/Production/Services/SandboxStore/LogLevel", "DEBUG") # Now setting a SandboxSE as the following: # ProductionSandboxSE # { # BackendType = DISET # AccessProtocol = dips # DIP # { # Host = localhost # Port = 9196 # ProtocolName = DIP
Script.parseCommandLine() args = Script.getPositionalArgs() setupName = args[0] # Where to store outputs if not os.path.isdir('%s/sandboxes' % setupName): os.makedirs('%s/sandboxes' % setupName) # now updating the CS from DIRAC.ConfigurationSystem.Client.CSAPI import CSAPI csAPI = CSAPI() csAPI.setOption( 'Systems/WorkloadManagement/Production/Services/SandboxStore/BasePath', '%s/sandboxes' % setupName) csAPI.setOption( 'Systems/WorkloadManagement/Production/Services/SandboxStore/LogLevel', 'DEBUG') # Now setting a SandboxSE as the following: # ProductionSandboxSE # { # BackendType = DISET # AccessProtocol.1 # { # Host = localhost # Port = 9196 # ProtocolName = DIP # Protocol = dips
# SecurityManager = FullSecurityManager # } # } # Databases # { # FileCatalogDB # { # DBName = FileCatalogDB # } # } # } # } from DIRAC.ConfigurationSystem.Client.CSAPI import CSAPI csAPI = CSAPI() for sct in ['Systems/DataManagement', 'Systems/DataManagement/Production', 'Systems/DataManagement/Production/Databases', 'Systems/DataManagement/Production/Databases/FileCatalogDB' ]: res = csAPI.createSection( sct ) if not res['OK']: print res['Message'] exit( 1 ) csAPI.setOption( 'Systems/DataManagement/Production/Databases/FileCatalogDB/DBName', 'FileCatalogDB' ) csAPI.setOption( 'Systems/DataManagement/Production/Databases/FileCatalogDB/Host', 'db-50098.cern.ch' ) csAPI.setOption( 'Systems/DataManagement/Production/Databases/FileCatalogDB/Port', '5501' ) csAPI.commit()
for sct in [ 'Systems/DataManagement', 'Systems/DataManagement/Production', 'Systems/DataManagement/Production/Databases', 'Systems/DataManagement/Production/Databases/FileCatalogDB', 'Systems/DataManagement/Production/Databases/MultiVOFileCatalogDB' ]: res = csAPI.createSection(sct) if not res['OK']: print(res['Message']) exit(1) dbHost = os.environ['DB_HOST'] dbPort = os.environ['DB_PORT'] csAPI.setOption( 'Systems/DataManagement/Production/Databases/FileCatalogDB/DBName', 'FileCatalogDB') csAPI.setOption( 'Systems/DataManagement/Production/Databases/FileCatalogDB/Host', dbHost) csAPI.setOption( 'Systems/DataManagement/Production/Databases/FileCatalogDB/Port', dbPort) csAPI.setOption( 'Systems/DataManagement/Production/Databases/MultiVOFileCatalogDB/DBName', 'MultiVOFileCatalogDB') csAPI.setOption( 'Systems/DataManagement/Production/Databases/MultiVOFileCatalogDB/Host', dbHost) csAPI.setOption( 'Systems/DataManagement/Production/Databases/MultiVOFileCatalogDB/Port', dbPort)
# } # } # Databases # { # FileCatalogDB # { # DBName = FileCatalogDB # } # } # } # } from DIRAC.ConfigurationSystem.Client.CSAPI import CSAPI csAPI = CSAPI() for sct in ['Systems/DataManagement/Production/Services', 'Systems/DataManagement/Production/Services/FileCatalog' ]: res = csAPI.createSection( sct ) if not res['OK']: print res['Message'] exit( 1 ) csAPI.setOption( 'Systems/DataManagement/Production/Services/FileCatalog/DirectoryManager', 'DirectoryClosure' ) csAPI.setOption( 'Systems/DataManagement/Production/Services/FileCatalog/FileManager', 'FileManagerPs' ) csAPI.setOption( 'Systems/DataManagement/Production/Services/FileCatalog/OldSecurityManager', 'DirectorySecurityManagerWithDelete' ) csAPI.setOption( 'Systems/DataManagement/Production/Services/FileCatalog/SecurityManager', 'PolicyBasedSecurityManager' ) csAPI.setOption( 'Systems/DataManagement/Production/Services/FileCatalog/SecurityPolicy', 'DIRAC/DataManagementSystem/DB/FileCatalogComponents/SecurityPolicies/VOMSPolicy' ) csAPI.setOption( 'Systems/DataManagement/Production/Services/FileCatalog/UniqueGUID', True ) csAPI.commit()
class CE2CSAgent(AgentModule): addressTo = "" addressFrom = "" voName = "" subject = "CE2CSAgent" alternativeBDIIs = [] def initialize(self): # TODO: Have no default and if no mail is found then use the diracAdmin group # and resolve all associated mail addresses. self.addressTo = self.am_getOption("MailTo", self.addressTo) self.addressFrom = self.am_getOption("MailFrom", self.addressFrom) # Create a list of alternative bdii urls self.alternativeBDIIs = self.am_getOption("AlternativeBDIIs", []) # Check if the bdii url is appended by a port number, if not append the default 2170 for index, url in enumerate(self.alternativeBDIIs): if not url.split(":")[-1].isdigit(): self.alternativeBDIIs[index] += ":2170" if self.addressTo and self.addressFrom: self.log.info("MailTo", self.addressTo) self.log.info("MailFrom", self.addressFrom) if self.alternativeBDIIs: self.log.info("AlternativeBDII URLs:", self.alternativeBDIIs) self.subject = "CE2CSAgent" # This sets the Default Proxy to used as that defined under # /Operations/Shifter/TestManager # the shifterProxy option in the Configuration can be used to change this default. self.am_setOption("shifterProxy", "TestManager") self.voName = self.am_getOption("VirtualOrganization", []) if not self.voName: vo = getVO() if vo: self.voName = [vo] if self.voName: self.log.info("Agent will manage VO(s) %s" % self.voName) else: self.log.fatal("VirtualOrganization option not defined for agent") return S_ERROR() self.csAPI = CSAPI() return self.csAPI.initialize() def execute(self): self.log.info("Start Execution") result = getProxyInfo() if not result["OK"]: return result infoDict = result["Value"] self.log.info(formatProxyInfoAsString(infoDict)) # Get a "fresh" copy of the CS data result = self.csAPI.downloadCSData() if not result["OK"]: self.log.warn("Could not download a fresh copy of the CS data", result["Message"]) self.__lookForCE() self.__infoFromCE() self.log.info("End Execution") return S_OK() def __checkAlternativeBDIISite(self, fun, *args): if self.alternativeBDIIs: self.log.warn("Trying to use alternative BDII sites") for site in self.alternativeBDIIs: self.log.info("Trying to contact alternative BDII", site) if len(args) == 1: result = fun(args[0], host=site) elif len(args) == 2: result = fun(args[0], vo=args[1], host=site) if not result["OK"]: self.log.error("Problem contacting alternative BDII", result["Message"]) elif result["OK"]: return result self.log.warn("Also checking alternative BDII sites failed") return result def __lookForCE(self): knownCEs = self.am_getOption("BannedCEs", []) result = gConfig.getSections("/Resources/Sites") if not result["OK"]: return grids = result["Value"] for grid in grids: result = gConfig.getSections("/Resources/Sites/%s" % grid) if not result["OK"]: return sites = result["Value"] for site in sites: opt = gConfig.getOptionsDict("/Resources/Sites/%s/%s" % (grid, site))["Value"] ces = List.fromChar(opt.get("CE", "")) knownCEs += ces response = "" for vo in self.voName: self.log.info("Check for available CEs for VO", vo) response = ldapCEState("", vo) if not response["OK"]: self.log.error("Error during BDII request", response["Message"]) response = self.__checkAlternativeBDIISite(ldapCEState, "", vo) return response newCEs = {} for queue in response["Value"]: try: queueName = queue["GlueCEUniqueID"] except: continue ceName = queueName.split(":")[0] if not ceName in knownCEs: newCEs[ceName] = None self.log.debug("New CE", ceName) body = "" possibleNewSites = [] for ce in newCEs.iterkeys(): response = ldapCluster(ce) if not response["OK"]: self.log.warn("Error during BDII request", response["Message"]) response = self.__checkAlternativeBDIISite(ldapCluster, ce) continue clusters = response["Value"] if len(clusters) != 1: self.log.warn("Error in cluster length", " CE %s Length %d" % (ce, len(clusters))) if len(clusters) == 0: continue cluster = clusters[0] fkey = cluster.get("GlueForeignKey", []) if type(fkey) == type(""): fkey = [fkey] nameBDII = None for entry in fkey: if entry.count("GlueSiteUniqueID"): nameBDII = entry.split("=")[1] break if not nameBDII: continue ceString = "CE: %s, GOCDB Name: %s" % (ce, nameBDII) self.log.info(ceString) response = ldapCE(ce) if not response["OK"]: self.log.warn("Error during BDII request", response["Message"]) response = self.__checkAlternativeBDIISite(ldapCE, ce) continue ceInfos = response["Value"] if len(ceInfos): ceInfo = ceInfos[0] systemName = ceInfo.get("GlueHostOperatingSystemName", "Unknown") systemVersion = ceInfo.get("GlueHostOperatingSystemVersion", "Unknown") systemRelease = ceInfo.get("GlueHostOperatingSystemRelease", "Unknown") else: systemName = "Unknown" systemVersion = "Unknown" systemRelease = "Unknown" osString = "SystemName: %s, SystemVersion: %s, SystemRelease: %s" % ( systemName, systemVersion, systemRelease, ) self.log.info(osString) response = ldapCEState(ce, vo) if not response["OK"]: self.log.warn("Error during BDII request", response["Message"]) response = self.__checkAlternativeBDIISite(ldapCEState, ce, vo) continue newCEString = "\n\n%s\n%s" % (ceString, osString) usefull = False ceStates = response["Value"] for ceState in ceStates: queueName = ceState.get("GlueCEUniqueID", "UnknownName") queueStatus = ceState.get("GlueCEStateStatus", "UnknownStatus") queueString = "%s %s" % (queueName, queueStatus) self.log.info(queueString) newCEString += "\n%s" % queueString if queueStatus.count("Production"): usefull = True if usefull: body += newCEString possibleNewSites.append("dirac-admin-add-site DIRACSiteName %s %s" % (nameBDII, ce)) if body: body = "We are glad to inform You about new CE(s) possibly suitable for %s:\n" % vo + body body += "\n\nTo suppress information about CE add its name to BannedCEs list." for possibleNewSite in possibleNewSites: body = "%s\n%s" % (body, possibleNewSite) self.log.info(body) if self.addressTo and self.addressFrom: notification = NotificationClient() result = notification.sendMail( self.addressTo, self.subject, body, self.addressFrom, localAttempt=False ) return S_OK() def __infoFromCE(self): sitesSection = cfgPath("Resources", "Sites") result = gConfig.getSections(sitesSection) if not result["OK"]: return grids = result["Value"] changed = False body = "" for grid in grids: gridSection = cfgPath(sitesSection, grid) result = gConfig.getSections(gridSection) if not result["OK"]: return sites = result["Value"] for site in sites: siteSection = cfgPath(gridSection, site) opt = gConfig.getOptionsDict(siteSection)["Value"] name = opt.get("Name", "") if name: coor = opt.get("Coordinates", "Unknown") mail = opt.get("Mail", "Unknown") result = ldapSite(name) if not result["OK"]: self.log.warn("BDII site %s: %s" % (name, result["Message"])) result = self.__checkAlternativeBDIISite(ldapSite, name) if result["OK"]: bdiiSites = result["Value"] if len(bdiiSites) == 0: self.log.warn(name, "Error in BDII: leng = 0") else: if not len(bdiiSites) == 1: self.log.warn(name, "Warning in BDII: leng = %d" % len(bdiiSites)) bdiiSite = bdiiSites[0] try: longitude = bdiiSite["GlueSiteLongitude"] latitude = bdiiSite["GlueSiteLatitude"] newcoor = "%s:%s" % (longitude, latitude) except: self.log.warn("Error in BDII coordinates") newcoor = "Unknown" try: newmail = bdiiSite["GlueSiteSysAdminContact"].split(":")[-1].strip() except: self.log.warn("Error in BDII mail") newmail = "Unknown" self.log.debug("%s %s %s" % (name, newcoor, newmail)) if newcoor != coor: self.log.info("%s" % (name), "%s -> %s" % (coor, newcoor)) if coor == "Unknown": self.csAPI.setOption(cfgPath(siteSection, "Coordinates"), newcoor) else: self.csAPI.modifyValue(cfgPath(siteSection, "Coordinates"), newcoor) changed = True if newmail != mail: self.log.info("%s" % (name), "%s -> %s" % (mail, newmail)) if mail == "Unknown": self.csAPI.setOption(cfgPath(siteSection, "Mail"), newmail) else: self.csAPI.modifyValue(cfgPath(siteSection, "Mail"), newmail) changed = True ceList = List.fromChar(opt.get("CE", "")) if not ceList: self.log.warn(site, "Empty site list") continue # result = gConfig.getSections( cfgPath( siteSection,'CEs' ) # if not result['OK']: # self.log.debug( "Section CEs:", result['Message'] ) for ce in ceList: ceSection = cfgPath(siteSection, "CEs", ce) result = gConfig.getOptionsDict(ceSection) if not result["OK"]: self.log.debug("Section CE", result["Message"]) wnTmpDir = "Unknown" arch = "Unknown" os = "Unknown" si00 = "Unknown" pilot = "Unknown" ceType = "Unknown" else: ceopt = result["Value"] wnTmpDir = ceopt.get("wnTmpDir", "Unknown") arch = ceopt.get("architecture", "Unknown") os = ceopt.get("OS", "Unknown") si00 = ceopt.get("SI00", "Unknown") pilot = ceopt.get("Pilot", "Unknown") ceType = ceopt.get("CEType", "Unknown") result = ldapCE(ce) if not result["OK"]: self.log.warn("Error in BDII for %s" % ce, result["Message"]) result = self.__checkAlternativeBDIISite(ldapCE, ce) continue try: bdiiCE = result["Value"][0] except: self.log.warn("Error in BDII for %s" % ce, result) bdiiCE = None if bdiiCE: try: newWNTmpDir = bdiiCE["GlueSubClusterWNTmpDir"] except: newWNTmpDir = "Unknown" if wnTmpDir != newWNTmpDir and newWNTmpDir != "Unknown": section = cfgPath(ceSection, "wnTmpDir") self.log.info(section, " -> ".join((wnTmpDir, newWNTmpDir))) if wnTmpDir == "Unknown": self.csAPI.setOption(section, newWNTmpDir) else: self.csAPI.modifyValue(section, newWNTmpDir) changed = True try: newArch = bdiiCE["GlueHostArchitecturePlatformType"] except: newArch = "Unknown" if arch != newArch and newArch != "Unknown": section = cfgPath(ceSection, "architecture") self.log.info(section, " -> ".join((arch, newArch))) if arch == "Unknown": self.csAPI.setOption(section, newArch) else: self.csAPI.modifyValue(section, newArch) changed = True try: newOS = "_".join( ( bdiiCE["GlueHostOperatingSystemName"], bdiiCE["GlueHostOperatingSystemVersion"], bdiiCE["GlueHostOperatingSystemRelease"], ) ) except: newOS = "Unknown" if os != newOS and newOS != "Unknown": section = cfgPath(ceSection, "OS") self.log.info(section, " -> ".join((os, newOS))) if os == "Unknown": self.csAPI.setOption(section, newOS) else: self.csAPI.modifyValue(section, newOS) changed = True body = body + "OS was changed %s -> %s for %s at %s\n" % (os, newOS, ce, site) try: newSI00 = bdiiCE["GlueHostBenchmarkSI00"] except: newSI00 = "Unknown" if si00 != newSI00 and newSI00 != "Unknown": section = cfgPath(ceSection, "SI00") self.log.info(section, " -> ".join((si00, newSI00))) if si00 == "Unknown": self.csAPI.setOption(section, newSI00) else: self.csAPI.modifyValue(section, newSI00) changed = True try: rte = bdiiCE["GlueHostApplicationSoftwareRunTimeEnvironment"] for vo in self.voName: if vo.lower() == "lhcb": if "VO-lhcb-pilot" in rte: newPilot = "True" else: newPilot = "False" else: newPilot = "Unknown" except: newPilot = "Unknown" if pilot != newPilot and newPilot != "Unknown": section = cfgPath(ceSection, "Pilot") self.log.info(section, " -> ".join((pilot, newPilot))) if pilot == "Unknown": self.csAPI.setOption(section, newPilot) else: self.csAPI.modifyValue(section, newPilot) changed = True newVO = "" for vo in self.voName: result = ldapCEState(ce, vo) # getBDIICEVOView if not result["OK"]: self.log.warn("Error in BDII for queue %s" % ce, result["Message"]) result = self.__checkAlternativeBDIISite(ldapCEState, ce, vo) continue try: queues = result["Value"] except: self.log.warn("Error in BDII for queue %s" % ce, result["Massage"]) continue newCEType = "Unknown" for queue in queues: try: queueType = queue["GlueCEImplementationName"] except: queueType = "Unknown" if newCEType == "Unknown": newCEType = queueType else: if queueType != newCEType: self.log.warn( "Error in BDII for CE %s " % ce, "different CE types %s %s" % (newCEType, queueType), ) if newCEType == "ARC-CE": newCEType = "ARC" if ceType != newCEType and newCEType != "Unknown": section = cfgPath(ceSection, "CEType") self.log.info(section, " -> ".join((ceType, newCEType))) if ceType == "Unknown": self.csAPI.setOption(section, newCEType) else: self.csAPI.modifyValue(section, newCEType) changed = True for queue in queues: try: queueName = queue["GlueCEUniqueID"].split("/")[-1] except: self.log.warn("Error in queueName ", queue) continue try: newMaxCPUTime = queue["GlueCEPolicyMaxCPUTime"] except: newMaxCPUTime = None newSI00 = None try: caps = queue["GlueCECapability"] if type(caps) == type(""): caps = [caps] for cap in caps: if cap.count("CPUScalingReferenceSI00"): newSI00 = cap.split("=")[-1] except: newSI00 = None queueSection = cfgPath(ceSection, "Queues", queueName) result = gConfig.getOptionsDict(queueSection) if not result["OK"]: self.log.warn("Section Queues", result["Message"]) maxCPUTime = "Unknown" si00 = "Unknown" allowedVOs = [""] else: queueOpt = result["Value"] maxCPUTime = queueOpt.get("maxCPUTime", "Unknown") si00 = queueOpt.get("SI00", "Unknown") if newVO == "": # Remember previous iteration, if none - read from conf allowedVOs = queueOpt.get("VO", "").split(",") else: # Else use newVO, as it can contain changes, which aren't in conf yet allowedVOs = newVO.split(",") if newMaxCPUTime and (maxCPUTime != newMaxCPUTime): section = cfgPath(queueSection, "maxCPUTime") self.log.info(section, " -> ".join((maxCPUTime, newMaxCPUTime))) if maxCPUTime == "Unknown": self.csAPI.setOption(section, newMaxCPUTime) else: self.csAPI.modifyValue(section, newMaxCPUTime) changed = True if newSI00 and (si00 != newSI00): section = cfgPath(queueSection, "SI00") self.log.info(section, " -> ".join((si00, newSI00))) if si00 == "Unknown": self.csAPI.setOption(section, newSI00) else: self.csAPI.modifyValue(section, newSI00) changed = True modifyVO = True # Flag saying if we need VO option to change newVO = "" if allowedVOs != [""]: for allowedVO in allowedVOs: allowedVO = allowedVO.strip() # Get rid of spaces newVO += allowedVO if allowedVO == vo: # Current VO has been already in list newVO = "" modifyVO = False # Don't change anything break # Skip next 'if', proceed to next VO newVO += ", " if modifyVO: section = cfgPath(queueSection, "VO") newVO += vo self.log.info(section, " -> ".join(("%s" % allowedVOs, newVO))) if allowedVOs == [""]: self.csAPI.setOption(section, newVO) else: self.csAPI.modifyValue(section, newVO) changed = True if changed: self.log.info(body) if body and self.addressTo and self.addressFrom: notification = NotificationClient() result = notification.sendMail(self.addressTo, self.subject, body, self.addressFrom, localAttempt=False) return self.csAPI.commit() else: self.log.info("No changes found") return S_OK()
class CVMFSAdder(object): """Container for all the objects and functions to add software to ILCDirac""" def __init__(self, cliParams ): from DIRAC.ConfigurationSystem.Client.CSAPI import CSAPI self.modifiedCS = False self.softSec = "/Operations/Defaults/AvailableTarBalls" self.mailadress = '*****@*****.**' self.cliParams = cliParams self.parameter = dict( softSec = self.softSec, platform = cliParams.platform, version = cliParams.version, basepath = cliParams.basePath, initsctipt = cliParams.initScriptLocation ) self.applications = cliParams.applicationSet self.detmodels = {} self.csAPI = CSAPI() def findDDSimDetectorModels( self ): """ find all detector models in lcgeo and fill the self.detmodels dictionary with Detmodel as key and path as value :returns: None """ for root,dirs,_files in os.walk( os.path.join( self.parameter["basepath"], "lcgeo" ) ): for direct in dirs: if root.endswith("compact"): ## the main xml file must have the same name as the folder xmlPath = os.path.join( root, direct, direct+".xml") if os.path.exists( xmlPath ): self.detmodels[direct] = xmlPath def checkConsistency(self): """checks if platform is defined, application exists, etc.""" gLogger.notice("Checking consistency") av_platforms = gConfig.getSections(self.softSec, []) if av_platforms['OK']: if not self.parameter['platform'] in av_platforms['Value']: gLogger.error("Platform %s unknown, available are %s." % (self.parameter['platform'], ", ".join(av_platforms['Value']))) gLogger.error("If yours is missing, add it in CS") return S_ERROR() else: gLogger.error("Could not find all platforms available in CS") return S_ERROR() for application in self.applications: av_apps = gConfig.getSections("%(softSec)s/%(platform)s/" % self.parameter + str(application), []) if not av_apps['OK']: gLogger.error("Could not find this application in the CS: '%s'" % application) gLogger.error("Add its section to the CS, if it is missing") return S_ERROR() gLogger.notice("All OK, continuing...") return S_OK() def commitToCS(self): """write changes to the CS to the server""" if self.modifiedCS and not self.cliParams.dryRun: gLogger.notice("Commiting changes to the CS") result = self.csAPI.commit() if not result[ 'OK' ]: gLogger.error('Commit failed with message = %s' % (result[ 'Message' ])) return S_ERROR("Failed to commit to CS") gLogger.info('Successfully committed changes to CS') else: gLogger.info('No modifications to CS required') return S_OK() def addAllToCS(self): """add all the applications to the CS, take care of special cases (mokka, ildconfig, ddsim,...)""" from ILCDIRAC.ILCTransformationSystem.Utilities.ReleaseHelper import insertCSSection for application in self.applications: csParameter = dict( CVMFSEnvScript = self.cliParams.initScriptLocation, CVMFSPath = self.parameter['basepath'] ) if application == 'mokka': csParameter['CVMFSDBSlice'] = self.cliParams.dbSliceLocation if application == 'ddsim': self.findDDSimDetectorModels() csPathModels = "Operations/Defaults/DDSimDetectorModels" csModels = { self.parameter["version"] : self.detmodels } insertCSSection( self.csAPI, csPathModels, csModels ) self.modifiedCS = True elif application.endswith('config'): del csParameter['CVMFSEnvScript'] csParameter['CVMFSPath'] = self.cliParams.configPath if self.cliParams.dbSliceLocation: csParameter['CVMFSDBSlice'] = self.cliParams.dbSliceLocation resInsert = self.insertApplicationToCS(application, csParameter) if not resInsert['OK']: return resInsert return S_OK() def insertApplicationToCS(self, name, csParameter): """add given application found via CVMFS to the CS""" pars = dict(self.parameter) pars['name'] = name gLogger.notice("%(name)s: Adding version %(version)s to the CS" % pars) existingVersions = gConfig.getSections("%(softSec)s/%(platform)s/%(name)s" % pars, []) if not existingVersions['OK']: gLogger.error("Could not find all versions available in CS: %s" % existingVersions['Message']) dexit(255) if pars['version'] in existingVersions['Value']: gLogger.always('Application %s %s for %s already in CS, nothing to do' % (name.lower(), pars['version'], pars['platform'])) return S_OK() csPath = self.softSec + ("/%(platform)s/%(name)s/%(version)s/" % pars) for par, val in csParameter.iteritems(): gLogger.notice("Add: %s = %s" %(csPath+par, val)) result = self.csAPI.setOption(csPath+par, val) if result['OK']: self.modifiedCS = True else: gLogger.error("Failure to add to CS", result['Message']) return S_ERROR("") return S_OK() def addSoftware(self): """run all the steps to add software to grid and CS""" resAdd = self.addAllToCS() if not resAdd['OK']: return resAdd resCommit = self.commitToCS() if not resCommit['OK']: return resCommit return S_OK()
userName = res["Value"]["username"] group = res["Value"]["group"] if not sites: Script.showHelp() DIRAC.exit(-1) catalogCFGBase = "/Resources/FileCatalogs/LcgFileCatalogCombined" banned = [] for site in sites: res = gConfig.getOptionsDict("%s/%s" % (catalogCFGBase, site)) if not res["OK"]: gLogger.error("The provided site (%s) does not have an associated catalog." % site) continue res = csAPI.setOption("%s/%s/Status" % (storageCFGBase, site), "InActive") if not res["OK"]: gLogger.error("Failed to update %s catalog status to InActive" % site) else: gLogger.debug("Successfully updated %s catalog status to InActive" % site) banned.append(site) if not banned: gLogger.error("Failed to ban any catalog mirrors") DIRAC.exit(-1) res = csAPI.commitChanges() if not res["OK"]: gLogger.error("Failed to commit changes to CS", res["Message"]) DIRAC.exit(-1)
#!/usr/bin/env python from __future__ import print_function import os from DIRAC.Core.Base import Script Script.parseCommandLine() from DIRAC.ConfigurationSystem.Client.CSAPI import CSAPI csAPI = CSAPI() csAPI.setOption('Resources/FileCatalogs/FileCatalog/Master', 'False') csAPI.setOption( 'Systems/DataManagement/Production/Services/MultiVOFileCatalog/SecurityManager', 'NoSecurityManager') # Final action: commit in CS res = csAPI.commit() if not res['OK']: print(res['Message']) exit(1)
class Bdii2CSAgent( AgentModule ): addressTo = '' addressFrom = '' voName = '' subject = "CE2CSAgent" alternativeBDIIs = [] def initialize( self ): self.addressTo = self.am_getOption( 'MailTo', self.addressTo ) self.addressFrom = self.am_getOption( 'MailFrom', self.addressFrom ) # Create a list of alternative bdii urls self.alternativeBDIIs = self.am_getOption( 'AlternativeBDIIs', [] ) # Check if the bdii url is appended by a port number, if not append the default 2170 for index, url in enumerate( self.alternativeBDIIs ): if not url.split( ':' )[-1].isdigit(): self.alternativeBDIIs[index] += ':2170' if self.addressTo and self.addressFrom: self.log.info( "MailTo", self.addressTo ) self.log.info( "MailFrom", self.addressFrom ) if self.alternativeBDIIs : self.log.info( "AlternativeBDII URLs:", self.alternativeBDIIs ) self.subject = "CE2CSAgent" self.processCEs = self.am_getOption( 'ProcessCEs', True ) self.processSEs = self.am_getOption( 'ProcessSEs', False ) self.voName = self.am_getOption( 'VirtualOrganization', [] ) if not self.voName: self.voName = self.am_getOption( 'VO', [] ) if not self.voName or ( len( self.voName ) == 1 and self.voName[0].lower() == 'all' ): # Get all VOs defined in the configuration self.voName = [] result = getVOs() if result['OK']: vos = result['Value'] for vo in vos: vomsVO = getVOOption( vo, "VOMSName" ) if vomsVO: self.voName.append( vomsVO ) if self.voName: self.log.info( "Agent will manage VO(s) %s" % self.voName ) else: self.log.fatal( "VirtualOrganization option not defined for agent" ) return S_ERROR() self.voBdiiCEDict = {} self.voBdiiSEDict = {} self.csAPI = CSAPI() return self.csAPI.initialize() def execute( self ): """ General agent execution method """ # Get a "fresh" copy of the CS data result = self.csAPI.downloadCSData() if not result['OK']: self.log.warn( "Could not download a fresh copy of the CS data", result[ 'Message' ] ) if self.processCEs: self.__lookForNewCEs() self.__updateCEs() if self.processSEs: self.__lookForNewSEs() self.__updateSEs() return S_OK() def __lookForNewCEs( self ): """ Look up BDII for CEs not yet present in the DIRAC CS """ bannedCEs = self.am_getOption( 'BannedCEs', [] ) result = getCEsFromCS() if not result['OK']: return result knownCEs = set( result['Value'] ) knownCEs = knownCEs.union( set( bannedCEs ) ) for vo in self.voName: result = self.__getBdiiCEInfo( vo ) if not result['OK']: continue bdiiInfo = result['Value'] result = getGridCEs( vo, bdiiInfo = bdiiInfo, ceBlackList = knownCEs ) if not result['OK']: self.log.error( 'Failed to get unused CEs', result['Message'] ) siteDict = result['Value'] body = '' for site in siteDict: newCEs = set( siteDict[site].keys() ) if not newCEs: continue ceString = '' for ce in newCEs: queueString = '' ceInfo = bdiiInfo[site]['CEs'][ce] ceString = "CE: %s, GOCDB Site Name: %s" % ( ce, site ) systemTuple = siteDict[site][ce]['System'] osString = "%s_%s_%s" % ( systemTuple ) newCEString = "\n%s\n%s\n" % ( ceString, osString ) for queue in ceInfo['Queues']: queueStatus = ceInfo['Queues'][queue].get( 'GlueCEStateStatus', 'UnknownStatus' ) if 'production' in queueStatus.lower(): ceType = ceInfo['Queues'][queue].get( 'GlueCEImplementationName', '' ) queueString += " %s %s %s\n" % ( queue, queueStatus, ceType ) if queueString: ceString = newCEString ceString += "Queues:\n" ceString += queueString if ceString: body += ceString if body: body = "\nWe are glad to inform You about new CE(s) possibly suitable for %s:\n" % vo + body body += "\n\nTo suppress information about CE add its name to BannedCEs list.\n" body += "Add new Sites/CEs for vo %s with the command:\n" % vo body += "dirac-admin-add-resources --vo %s --ce\n" % vo self.log.info( body ) if self.addressTo and self.addressFrom: notification = NotificationClient() result = notification.sendMail( self.addressTo, self.subject, body, self.addressFrom, localAttempt = False ) if not result['OK']: self.log.error( 'Can not send new site notification mail', result['Message'] ) return S_OK() def __getBdiiCEInfo( self, vo ): if vo in self.voBdiiCEDict: return S_OK( self.voBdiiCEDict[vo] ) self.log.info( "Check for available CEs for VO", vo ) result = getBdiiCEInfo( vo ) message = '' if not result['OK']: message = result['Message'] for bdii in self.alternativeBDIIs : result = getBdiiCEInfo( vo, host = bdii ) if result['OK']: break if not result['OK']: if message: self.log.error( "Error during BDII request", message ) else: self.log.error( "Error during BDII request", result['Message'] ) else: self.voBdiiCEDict[vo] = result['Value'] return result def __getBdiiSEInfo( self, vo ): if vo in self.voBdiiSEDict: return S_OK( self.voBdiiSEDict[vo] ) self.log.info( "Check for available SEs for VO", vo ) result = getBdiiSEInfo( vo ) message = '' if not result['OK']: message = result['Message'] for bdii in self.alternativeBDIIs : result = getBdiiSEInfo( vo, host = bdii ) if result['OK']: break if not result['OK']: if message: self.log.error( "Error during BDII request", message ) else: self.log.error( "Error during BDII request", result['Message'] ) else: self.voBdiiSEDict[vo] = result['Value'] return result def __updateCEs( self ): """ Update the Site/CE/queue settings in the CS if they were changed in the BDII """ bdiiChangeSet = set() for vo in self.voName: result = self.__getBdiiCEInfo( vo ) if not result['OK']: continue ceBdiiDict = result['Value'] result = getSiteUpdates( vo, bdiiInfo = ceBdiiDict, log = self.log ) if not result['OK']: continue bdiiChangeSet = bdiiChangeSet.union( result['Value'] ) # We have collected all the changes, consolidate VO settings result = self.__updateCS( bdiiChangeSet ) return result def __updateCS( self, bdiiChangeSet ): queueVODict = {} changeSet = set() for entry in bdiiChangeSet: section, option , _value, new_value = entry if option == "VO": queueVODict.setdefault( section, set() ) queueVODict[section] = queueVODict[section].union( set( new_value.split( ',' ) ) ) else: changeSet.add( entry ) for section, VOs in queueVODict.items(): changeSet.add( ( section, 'VO', '', ','.join( VOs ) ) ) if changeSet: changeList = list( changeSet ) changeList.sort() body = '\n'.join( [ "%s/%s %s -> %s" % entry for entry in changeList ] ) if body and self.addressTo and self.addressFrom: notification = NotificationClient() result = notification.sendMail( self.addressTo, self.subject, body, self.addressFrom, localAttempt = False ) if body: self.log.info( 'The following configuration changes were detected:' ) self.log.info( body ) for section, option, value, new_value in changeSet: if value == 'Unknown' or not value: self.csAPI.setOption( cfgPath( section, option ), new_value ) else: self.csAPI.modifyValue( cfgPath( section, option ), new_value ) result = self.csAPI.commit() if not result['OK']: self.log.error( "Error while committing to CS", result['Message'] ) else: self.log.info( "Successfully committed %d changes to CS" % len( changeList ) ) return result else: self.log.info( "No changes found" ) return S_OK() def __lookForNewSEs( self ): """ Look up BDII for SEs not yet present in the DIRAC CS """ bannedSEs = self.am_getOption( 'BannedSEs', [] ) result = getSEsFromCS() if not result['OK']: return result knownSEs = set( result['Value'] ) knownSEs = knownSEs.union( set( bannedSEs ) ) for vo in self.voName: result = self.__getBdiiSEInfo( vo ) if not result['OK']: continue bdiiInfo = result['Value'] result = getGridSRMs( vo, bdiiInfo = bdiiInfo, srmBlackList = knownSEs ) if not result['OK']: continue siteDict = result['Value'] body = '' for site in siteDict: newSEs = set( siteDict[site].keys() ) if not newSEs: continue for se in newSEs: body += '\n New SE %s available at site %s:\n' % ( se, site ) backend = siteDict[site][se]['SE'].get( 'GlueSEImplementationName', 'Unknown' ) size = siteDict[site][se]['SE'].get( 'GlueSESizeTotal', 'Unknown' ) body += ' Backend %s, Size %s' % ( backend, size ) if body: body = "\nWe are glad to inform You about new SE(s) possibly suitable for %s:\n" % vo + body body += "\n\nTo suppress information about an SE add its name to BannedSEs list.\n" body += "Add new SEs for vo %s with the command:\n" % vo body += "dirac-admin-add-resources --vo %s --se\n" % vo self.log.info( body ) if self.addressTo and self.addressFrom: notification = NotificationClient() result = notification.sendMail( self.addressTo, self.subject, body, self.addressFrom, localAttempt = False ) if not result['OK']: self.log.error( 'Can not send new site notification mail', result['Message'] ) return S_OK() def __updateSEs( self ): """ Update the Storage Element settings in the CS if they were changed in the BDII """ bdiiChangeSet = set() for vo in self.voName: result = self.__getBdiiSEInfo( vo ) if not result['OK']: continue seBdiiDict = result['Value'] result = getSRMUpdates( vo, bdiiInfo = seBdiiDict ) if not result['OK']: continue bdiiChangeSet = bdiiChangeSet.union( result['Value'] ) # We have collected all the changes, consolidate VO settings result = self.__updateCS( bdiiChangeSet ) return result
class Bdii2CSAgent(AgentModule): def __init__(self, *args, **kwargs): """ Defines default parameters """ super(Bdii2CSAgent, self).__init__(*args, **kwargs) self.addressTo = '' self.addressFrom = '' self.voName = [] self.subject = self.am_getModuleParam('fullName') self.alternativeBDIIs = [] self.voBdiiCEDict = {} self.voBdiiSEDict = {} self.host = 'lcg-bdii.cern.ch:2170' self.glue2URLs = [] self.glue2Only = True self.csAPI = None # What to get self.processCEs = True self.selectedSites = [] # Update the CS or not? self.dryRun = False def initialize(self): """ Gets run paramaters from the configuration """ self.addressTo = self.am_getOption('MailTo', self.addressTo) self.addressFrom = self.am_getOption('MailFrom', self.addressFrom) # Create a list of alternative bdii urls self.alternativeBDIIs = self.am_getOption('AlternativeBDIIs', self.alternativeBDIIs) self.host = self.am_getOption('Host', self.host) self.glue2URLs = self.am_getOption('GLUE2URLs', self.glue2URLs) self.glue2Only = self.am_getOption('GLUE2Only', self.glue2Only) # Check if the bdii url is appended by a port number, if not append the default 2170 for index, url in enumerate(self.alternativeBDIIs): if not url.split(':')[-1].isdigit(): self.alternativeBDIIs[index] += ':2170' if self.addressTo and self.addressFrom: self.log.info("MailTo", self.addressTo) self.log.info("MailFrom", self.addressFrom) if self.alternativeBDIIs: self.log.info("AlternativeBDII URLs:", self.alternativeBDIIs) self.processCEs = self.am_getOption('ProcessCEs', self.processCEs) self.selectedSites = self.am_getOption('SelectedSites', []) self.dryRun = self.am_getOption('DryRun', self.dryRun) self.voName = self.am_getOption('VirtualOrganization', self.voName) if not self.voName: self.voName = self.am_getOption('VO', []) if not self.voName or (len(self.voName) == 1 and self.voName[0].lower() == 'all'): # Get all VOs defined in the configuration self.voName = [] result = getVOs() if result['OK']: vos = result['Value'] for vo in vos: vomsVO = getVOOption(vo, "VOMSName") if vomsVO: self.voName.append(vomsVO) if self.voName: self.log.info("Agent will manage VO(s) %s" % self.voName) else: self.log.fatal("VirtualOrganization option not defined for agent") return S_ERROR() self.csAPI = CSAPI() return self.csAPI.initialize() def execute(self): """ General agent execution method """ self.voBdiiCEDict = {} # Get a "fresh" copy of the CS data result = self.csAPI.downloadCSData() if not result['OK']: self.log.warn("Could not download a fresh copy of the CS data", result['Message']) # Refresh the configuration from the master server gConfig.forceRefresh(fromMaster=True) if self.processCEs: self.__lookForNewCEs() self.__updateCEs() return S_OK() def __lookForNewCEs(self): """ Look up BDII for CEs not yet present in the DIRAC CS """ bannedCEs = self.am_getOption('BannedCEs', []) for vo in self.voName: # get the known CEs for a given VO, so we can know the unknowns, or no longer supported, # for a VO res = getQueues(community=vo) if not res['OK']: return res knownCEs = set() for _site, ces in res['Value'].items(): knownCEs.update(ces) knownCEs.update(bannedCEs) result = self.__getBdiiCEInfo(vo) if not result['OK']: continue bdiiInfo = result['Value'] result = getGridCEs(vo, bdiiInfo=bdiiInfo, ceBlackList=knownCEs) if not result['OK']: self.log.error('Failed to get unused CEs', result['Message']) continue # next VO siteDict = result['Value'] unknownCEs = set(result['UnknownCEs']) - set(bannedCEs) body = '' for site in siteDict: newCEs = set(siteDict[site]) # pylint: disable=no-member if not newCEs: continue ceString = '' for ce in newCEs: queueString = '' ceInfo = bdiiInfo[site]['CEs'][ce] newCEString = "CE: %s, GOCDB Site Name: %s" % (ce, site) systemTuple = siteDict[site][ce]['System'] osString = "%s_%s_%s" % (systemTuple) newCEString = "\n%s\n%s\n" % (newCEString, osString) for queue in ceInfo['Queues']: queueStatus = ceInfo['Queues'][queue].get( 'GlueCEStateStatus', 'UnknownStatus') if 'production' in queueStatus.lower(): ceType = ceInfo['Queues'][queue].get( 'GlueCEImplementationName', '') queueString += " %s %s %s\n" % ( queue, queueStatus, ceType) if queueString: ceString += newCEString ceString += "Queues:\n" ceString += queueString if ceString: body += ceString if siteDict: body = "\nWe are glad to inform You about new CE(s) possibly suitable for %s:\n" % vo + body body += "\n\nTo suppress information about CE add its name to BannedCEs list.\n" body += "Add new Sites/CEs for vo %s with the command:\n" % vo body += "dirac-admin-add-resources --vo %s --ce\n" % vo if unknownCEs: body += '\n\n' body += 'There is no (longer) information about the following CEs for the %s VO.\n' % vo body += '\n'.join(sorted(unknownCEs)) body += '\n\n' if body: self.log.info(body) if self.addressTo and self.addressFrom: notification = NotificationClient() result = notification.sendMail(self.addressTo, self.subject, body, self.addressFrom, localAttempt=False) if not result['OK']: self.log.error( 'Can not send new site notification mail', result['Message']) return S_OK() def __getBdiiCEInfo(self, vo): if vo in self.voBdiiCEDict: return S_OK(self.voBdiiCEDict[vo]) self.log.info("Check for available CEs for VO", vo) totalResult = S_OK({}) message = '' mainResult = getBdiiCEInfo(vo, host=self.host, glue2=self.glue2Only) if not mainResult['OK']: self.log.error("Failed getting information from default bdii", mainResult['Message']) message = mainResult['Message'] for bdii in reversed(self.alternativeBDIIs): resultAlt = getBdiiCEInfo(vo, host=bdii, glue2=self.glue2Only) if resultAlt['OK']: totalResult['Value'].update(resultAlt['Value']) else: self.log.error("Failed getting information from %s " % bdii, resultAlt['Message']) message = (message + "\n" + resultAlt['Message']).strip() for glue2URL in self.glue2URLs: if self.glue2Only: break resultGlue2 = getBdiiCEInfo(vo, host=glue2URL, glue2=True) if resultGlue2['OK']: totalResult['Value'].update(resultGlue2['Value']) else: self.log.error( "Failed getting GLUE2 information for", "%s, %s: %s" % (glue2URL, vo, resultGlue2['Message'])) message = (message + "\n" + resultGlue2['Message']).strip() if mainResult['OK']: totalResult['Value'].update(mainResult['Value']) if not totalResult[ 'Value'] and message: # Dict is empty and we have an error message self.log.error("Error during BDII request", message) totalResult = S_ERROR(message) else: self.voBdiiCEDict[vo] = totalResult['Value'] self.__purgeSites(totalResult['Value']) return totalResult def __updateCEs(self): """ Update the Site/CE/queue settings in the CS if they were changed in the BDII """ bdiiChangeSet = set() for vo in self.voName: result = self.__getBdiiCEInfo(vo) if not result['OK']: continue ceBdiiDict = result['Value'] result = getSiteUpdates(vo, bdiiInfo=ceBdiiDict, log=self.log) if not result['OK']: continue bdiiChangeSet = bdiiChangeSet.union(result['Value']) # We have collected all the changes, consolidate VO settings result = self.__updateCS(bdiiChangeSet) return result def __purgeSites(self, ceBdiiDict): """Remove all sites that are not in self.selectedSites. Modifies the ceBdiiDict! """ if not self.selectedSites: return for site in list(ceBdiiDict): ces = list(ceBdiiDict[site]['CEs']) if not ces: self.log.error("No CE information for site:", site) continue siteInCS = 'Not_In_CS' for ce in ces: res = getCESiteMapping(ce) if not res['OK']: self.log.error("Failed to get DIRAC site name for ce", "%s: %s" % (ce, res['Message'])) continue # if the ce is not in the CS the returned value will be empty if ce in res['Value']: siteInCS = res['Value'][ce] break self.log.debug("Checking site %s (%s), aka %s" % (site, ces, siteInCS)) if siteInCS in self.selectedSites: continue self.log.info("Dropping site %s, aka %s" % (site, siteInCS)) ceBdiiDict.pop(site) return def __updateCS(self, bdiiChangeSet): queueVODict = {} changeSet = set() for entry in bdiiChangeSet: section, option, _value, new_value = entry if option == "VO": queueVODict.setdefault(section, set()) queueVODict[section] = queueVODict[section].union( set(new_value.split(','))) else: changeSet.add(entry) for section, VOs in queueVODict.items(): # can be an iterator changeSet.add((section, 'VO', '', ','.join(VOs))) if changeSet: changeList = sorted(changeSet) body = '\n'.join( ["%s/%s %s -> %s" % entry for entry in changeList]) if body and self.addressTo and self.addressFrom: notification = NotificationClient() result = notification.sendMail(self.addressTo, self.subject, body, self.addressFrom, localAttempt=False) if body: self.log.info( 'The following configuration changes were detected:') self.log.info(body) for section, option, value, new_value in changeSet: if value == 'Unknown' or not value: self.csAPI.setOption(cfgPath(section, option), new_value) else: self.csAPI.modifyValue(cfgPath(section, option), new_value) if self.dryRun: self.log.info("Dry Run: CS won't be updated") self.csAPI.showDiff() else: result = self.csAPI.commit() if not result['OK']: self.log.error("Error while committing to CS", result['Message']) else: self.log.info("Successfully committed %d changes to CS" % len(changeList)) return result else: self.log.info("No changes found") return S_OK()
class CVMFSAdder(object): """Container for all the objects and functions to add software to ILCDirac""" def __init__(self, cliParams): from DIRAC.ConfigurationSystem.Client.CSAPI import CSAPI self.modifiedCS = False self.softSec = "/Operations/Defaults/AvailableTarBalls" self.mailadress = '*****@*****.**' self.cliParams = cliParams self.parameter = dict(softSec=self.softSec, platform=cliParams.platform, version=cliParams.version, basepath=cliParams.basePath, initsctipt=cliParams.initScriptLocation) self.applications = cliParams.applicationSet self.detmodels = {} self.csAPI = CSAPI() def findDDSimDetectorModels(self): """ find all detector models in lcgeo and fill the self.detmodels dictionary with Detmodel as key and path as value :returns: None """ for root, dirs, _files in os.walk( os.path.join(self.parameter["basepath"], "lcgeo")): for direct in dirs: if root.endswith("compact"): ## the main xml file must have the same name as the folder xmlPath = os.path.join(root, direct, direct + ".xml") if os.path.exists(xmlPath): self.detmodels[direct] = xmlPath def checkConsistency(self): """checks if platform is defined, application exists, etc.""" gLogger.notice("Checking consistency") av_platforms = gConfig.getSections(self.softSec, []) if av_platforms['OK']: if not self.parameter['platform'] in av_platforms['Value']: gLogger.error("Platform %s unknown, available are %s." % (self.parameter['platform'], ", ".join( av_platforms['Value']))) gLogger.error("If yours is missing, add it in CS") return S_ERROR() else: gLogger.error("Could not find all platforms available in CS") return S_ERROR() for application in self.applications: av_apps = gConfig.getSections( "%(softSec)s/%(platform)s/" % self.parameter + str(application), []) if not av_apps['OK']: gLogger.error( "Could not find this application in the CS: '%s'" % application) gLogger.error("Add its section to the CS, if it is missing") return S_ERROR() gLogger.notice("All OK, continuing...") return S_OK() def commitToCS(self): """write changes to the CS to the server""" if self.modifiedCS and not self.cliParams.dryRun: gLogger.notice("Commiting changes to the CS") result = self.csAPI.commit() if not result['OK']: gLogger.error('Commit failed with message = %s' % (result['Message'])) return S_ERROR("Failed to commit to CS") gLogger.info('Successfully committed changes to CS') else: gLogger.info('No modifications to CS required') return S_OK() def addAllToCS(self): """add all the applications to the CS, take care of special cases (mokka, ildconfig, ddsim,...)""" from ILCDIRAC.ILCTransformationSystem.Utilities.ReleaseHelper import insertCSSection for application in self.applications: csParameter = dict( CVMFSEnvScript=self.cliParams.initScriptLocation, CVMFSPath=self.parameter['basepath']) if application == 'mokka': csParameter['CVMFSDBSlice'] = self.cliParams.dbSliceLocation if application == 'ddsim': self.findDDSimDetectorModels() csPathModels = "Operations/Defaults/DDSimDetectorModels" csModels = {self.parameter["version"]: self.detmodels} insertCSSection(self.csAPI, csPathModels, csModels) self.modifiedCS = True elif application.endswith('config'): del csParameter['CVMFSEnvScript'] csParameter['CVMFSPath'] = self.cliParams.configPath if self.cliParams.dbSliceLocation: csParameter[ 'CVMFSDBSlice'] = self.cliParams.dbSliceLocation resInsert = self.insertApplicationToCS(application, csParameter) if not resInsert['OK']: return resInsert return S_OK() def insertApplicationToCS(self, name, csParameter): """add given application found via CVMFS to the CS""" pars = dict(self.parameter) pars['name'] = name gLogger.notice("%(name)s: Adding version %(version)s to the CS" % pars) existingVersions = gConfig.getSections( "%(softSec)s/%(platform)s/%(name)s" % pars, []) if not existingVersions['OK']: gLogger.error("Could not find all versions available in CS: %s" % existingVersions['Message']) dexit(255) if pars['version'] in existingVersions['Value']: gLogger.always( 'Application %s %s for %s already in CS, nothing to do' % (name.lower(), pars['version'], pars['platform'])) return S_OK() csPath = self.softSec + ("/%(platform)s/%(name)s/%(version)s/" % pars) for par, val in csParameter.iteritems(): gLogger.notice("Add: %s = %s" % (csPath + par, val)) result = self.csAPI.setOption(csPath + par, val) if result['OK']: self.modifiedCS = True else: gLogger.error("Failure to add to CS", result['Message']) return S_ERROR("") return S_OK() def addSoftware(self): """run all the steps to add software to grid and CS""" resAdd = self.addAllToCS() if not resAdd['OK']: return resAdd resCommit = self.commitToCS() if not resCommit['OK']: return resCommit return S_OK()
class GOCDB2CSAgent (AgentModule): """ Class to retrieve information about service endpoints from GOCDB and update configuration stored by CS """ def __init__(self, *args, **kwargs): """ c'tor """ super(GOCDB2CSAgent, self).__init__(*args, **kwargs) self.GOCDBClient = None self.csAPI = None self.dryRun = False def initialize(self): """ Run at the agent initialization (normally every 500 cycles) """ # client to connect to GOCDB self.GOCDBClient = GOCDBClient() self.dryRun = self.am_getOption('DryRun', self.dryRun) # API needed to update configuration stored by CS self.csAPI = CSAPI() return self.csAPI.initialize() def execute(self): """ Execute GOCDB queries according to the function map and user request (options in configuration). """ # __functionMap is at the end of the class definition for option, functionCall in GOCDB2CSAgent.__functionMap.iteritems(): optionValue = self.am_getOption(option, True) if optionValue: result = functionCall(self) if not result['OK']: self.log.error("%s() failed with message: %s" % (functionCall.__name__, result['Message'])) else: self.log.info("Successfully executed %s" % functionCall.__name__) return S_OK() def updatePerfSONARConfiguration(self): """ Get current status of perfSONAR endpoints from GOCDB and update CS configuration accordingly. """ log = self.log.getSubLogger('updatePerfSONAREndpoints') log.debug('Begin function ...') # get endpoints result = self.__getPerfSONAREndpoints() if not result['OK']: log.error("__getPerfSONAREndpoints() failed with message: %s" % result['Message']) return S_ERROR('Unable to fetch perfSONAR endpoints from GOCDB.') endpointList = result['Value'] # add DIRAC site name result = self.__addDIRACSiteName(endpointList) if not result['OK']: log.error("__addDIRACSiteName() failed with message: %s" % result['Message']) return S_ERROR('Unable to extend the list with DIRAC site names.') extendedEndpointList = result['Value'] # prepare dictionary with new configuration result = self.__preparePerfSONARConfiguration(extendedEndpointList) if not result['OK']: log.error("__preparePerfSONARConfiguration() failed with message: %s" % result['Message']) return S_ERROR('Unable to prepare a new perfSONAR configuration.') finalConfiguration = result['Value'] # update configuration according to the final status of endpoints self.__updateConfiguration(finalConfiguration) log.debug("Configuration updated succesfully") log.debug('End function.') return S_OK() def __getPerfSONAREndpoints(self): """ Retrieve perfSONAR endpoint information directly from GOCDB. :return: List of perfSONAR endpoints (dictionaries) as stored by GOCDB. """ log = self.log.getSubLogger('__getPerfSONAREndpoints') log.debug('Begin function ...') # get perfSONAR endpoints (latency and bandwidth) form GOCDB endpointList = [] for endpointType in ['Latency', 'Bandwidth']: result = self.GOCDBClient.getServiceEndpointInfo('service_type', 'net.perfSONAR.%s' % endpointType) if not result['OK']: log.error("getServiceEndpointInfo() failed with message: %s" % result['Message']) return S_ERROR('Could not fetch %s endpoints from GOCDB' % endpointType.lower()) log.debug('Number of %s endpoints: %s' % (endpointType.lower(), len(result['Value']))) endpointList.extend(result['Value']) log.debug('Number of perfSONAR endpoints: %s' % len(endpointList)) log.debug('End function.') return S_OK(endpointList) def __preparePerfSONARConfiguration(self, endpointList): """ Prepare a dictionary with a new CS configuration of perfSONAR endpoints. :return: Dictionary where keys are configuration paths (options and sections) and values are values of corresponding options or None in case of a path pointing to a section. """ log = self.log.getSubLogger('__preparePerfSONARConfiguration') log.debug('Begin function ...') # static elements of a path rootPath = '/Resources/Sites' extPath = 'Network' baseOptionName = 'Enabled' options = {baseOptionName: 'True', 'ServiceType': 'perfSONAR'} # enable GOCDB endpoints in configuration newConfiguration = {} for endpoint in endpointList: if endpoint['DIRACSITENAME'] is None: continue split = endpoint['DIRACSITENAME'].split('.') path = cfgPath(rootPath, split[0], endpoint['DIRACSITENAME'], extPath, endpoint['HOSTNAME']) for name, defaultValue in options.iteritems(): newConfiguration[cfgPath(path, name)] = defaultValue # get current configuration currentConfiguration = {} for option in options.iterkeys(): result = gConfig.getConfigurationTree(rootPath, extPath + '/', '/' + option) if not result['OK']: log.error("getConfigurationTree() failed with message: %s" % result['Message']) return S_ERROR('Unable to fetch perfSONAR endpoints from CS.') currentConfiguration.update(result['Value']) # disable endpoints that disappeared in GOCDB removedElements = set(currentConfiguration) - set(newConfiguration) newElements = set(newConfiguration) - set(currentConfiguration) addedEndpoints = len(newElements) / len(options) disabledEndpoints = 0 for path in removedElements: if baseOptionName in path: newConfiguration[path] = 'False' if currentConfiguration[path] != 'False': disabledEndpoints = disabledEndpoints + 1 # inform what will be changed if addedEndpoints > 0: self.log.info("%s new perfSONAR endpoints will be added to the configuration" % addedEndpoints) if disabledEndpoints > 0: self.log.info("%s old perfSONAR endpoints will be disable in the configuration" % disabledEndpoints) if addedEndpoints == 0 and disabledEndpoints == 0: self.log.info("perfSONAR configuration is up-to-date") log.debug('End function.') return S_OK(newConfiguration) def __addDIRACSiteName(self, inputList): """ Extend given list of GOCDB endpoints with DIRAC site name, i.e. add an entry "DIRACSITENAME" in dictionaries that describe endpoints. If given site name could not be found "DIRACSITENAME" is set to 'None'. :return: List of perfSONAR endpoints (dictionaries). """ log = self.log.getSubLogger('__addDIRACSiteName') log.debug('Begin function ...') # get site name dictionary result = getDIRACGOCDictionary() if not result['OK']: log.error("getDIRACGOCDictionary() failed with message: %s" % result['Message']) return S_ERROR('Could not get site name dictionary') # reverse the dictionary (assume 1 to 1 relation) DIRACGOCDict = result['Value'] GOCDIRACDict = dict(zip(DIRACGOCDict.values(), DIRACGOCDict.keys())) # add DIRAC site names outputList = [] for entry in inputList: try: entry['DIRACSITENAME'] = GOCDIRACDict[entry['SITENAME']] except KeyError: self.log.warn("No dictionary entry for %s. " % entry['SITENAME']) entry['DIRACSITENAME'] = None outputList.append(entry) log.debug('End function.') return S_OK(outputList) def __updateConfiguration(self, setElements=None, delElements=None): """ Update configuration stored by CS. """ if setElements is None: setElements = {} if delElements is None: delElements = [] log = self.log.getSubLogger('__updateConfiguration') log.debug('Begin function ...') # assure existence and proper value of a section or an option for path, value in setElements.iteritems(): if value is None: section = path else: split = path.rsplit('/', 1) section = split[0] try: result = self.csAPI.createSection(section) if not result['OK']: log.error("createSection() failed with message: %s" % result['Message']) except Exception as e: log.error("Exception in createSection(): %s" % repr(e).replace(',)', ')')) if value is not None: try: result = self.csAPI.setOption(path, value) if not result['OK']: log.error("setOption() failed with message: %s" % result['Message']) except Exception as e: log.error("Exception in setOption(): %s" % repr(e).replace(',)', ')')) # delete elements in the configuration for path in delElements: result = self.csAPI.delOption(path) if not result['OK']: log.warn("delOption() failed with message: %s" % result['Message']) result = self.csAPI.delSection(path) if not result['OK']: log.warn("delSection() failed with message: %s" % result['Message']) if self.dryRun: log.info("Dry Run: CS won't be updated") self.csAPI.showDiff() else: # update configuration stored by CS result = self.csAPI.commit() if not result['OK']: log.error("commit() failed with message: %s" % result['Message']) return S_ERROR("Could not commit changes to CS.") else: log.info("Committed changes to CS") log.debug('End function.') return S_OK() # define mapping between an agent option in the configuration and a function call __functionMap = {'UpdatePerfSONARS': updatePerfSONARConfiguration, }
userName = res['Value']['username'] group = res['Value']['group'] if not sites: Script.showHelp() DIRAC.exit( -1 ) catalogCFGBase = "/Resources/FileCatalogs/LcgFileCatalogCombined" allowed = [] for site in sites: res = gConfig.getOptionsDict( '%s/%s' % ( catalogCFGBase, site ) ) if not res['OK']: gLogger.error( "The provided site (%s) does not have an associated catalog." % site ) continue res = csAPI.setOption( "%s/%s/Status" % ( catalogCFGBase, site ), "Active" ) if not res['OK']: gLogger.error( "Failed to update %s catalog status to Active" % site ) else: gLogger.debug( "Successfully updated %s catalog status to Active" % site ) allowed.append( site ) if not allowed: gLogger.error( "Failed to allow any catalog mirrors" ) DIRAC.exit( -1 ) res = csAPI.commitChanges() if not res['OK']: gLogger.error( "Failed to commit changes to CS", res['Message'] ) DIRAC.exit( -1 )
class GOCDB2CSAgent(AgentModule): """ Class to retrieve information about service endpoints from GOCDB and update configuration stored by CS """ def __init__(self, *args, **kwargs): """ c'tor """ super(GOCDB2CSAgent, self).__init__(*args, **kwargs) self.GOCDBClient = None self.csAPI = None self.dryRun = False def initialize(self): """ Run at the agent initialization (normally every 500 cycles) """ # client to connect to GOCDB self.GOCDBClient = GOCDBClient() self.dryRun = self.am_getOption('DryRun', self.dryRun) # API needed to update configuration stored by CS self.csAPI = CSAPI() return self.csAPI.initialize() def execute(self): """ Execute GOCDB queries according to the function map and user request (options in configuration). """ # __functionMap is at the end of the class definition for option, functionCall in GOCDB2CSAgent.__functionMap.iteritems(): optionValue = self.am_getOption(option, True) if optionValue: result = functionCall(self) if not result['OK']: self.log.error("%s() failed with message: %s" % (functionCall.__name__, result['Message'])) else: self.log.info("Successfully executed %s" % functionCall.__name__) return S_OK() def updatePerfSONARConfiguration(self): """ Get current status of perfSONAR endpoints from GOCDB and update CS configuration accordingly. """ log = self.log.getSubLogger('updatePerfSONAREndpoints') log.debug('Begin function ...') # get endpoints result = self.__getPerfSONAREndpoints() if not result['OK']: log.error("__getPerfSONAREndpoints() failed with message: %s" % result['Message']) return S_ERROR('Unable to fetch perfSONAR endpoints from GOCDB.') endpointList = result['Value'] # add DIRAC site name result = self.__addDIRACSiteName(endpointList) if not result['OK']: log.error("__addDIRACSiteName() failed with message: %s" % result['Message']) return S_ERROR('Unable to extend the list with DIRAC site names.') extendedEndpointList = result['Value'] # prepare dictionary with new configuration result = self.__preparePerfSONARConfiguration(extendedEndpointList) if not result['OK']: log.error( "__preparePerfSONARConfiguration() failed with message: %s" % result['Message']) return S_ERROR('Unable to prepare a new perfSONAR configuration.') finalConfiguration = result['Value'] # update configuration according to the final status of endpoints self.__updateConfiguration(finalConfiguration) log.debug("Configuration updated succesfully") log.debug('End function.') return S_OK() def __getPerfSONAREndpoints(self): """ Retrieve perfSONAR endpoint information directly from GOCDB. :return: List of perfSONAR endpoints (dictionaries) as stored by GOCDB. """ log = self.log.getSubLogger('__getPerfSONAREndpoints') log.debug('Begin function ...') # get perfSONAR endpoints (latency and bandwidth) form GOCDB endpointList = [] for endpointType in ['Latency', 'Bandwidth']: result = self.GOCDBClient.getServiceEndpointInfo( 'service_type', 'net.perfSONAR.%s' % endpointType) if not result['OK']: log.error("getServiceEndpointInfo() failed with message: %s" % result['Message']) return S_ERROR('Could not fetch %s endpoints from GOCDB' % endpointType.lower()) log.debug('Number of %s endpoints: %s' % (endpointType.lower(), len(result['Value']))) endpointList.extend(result['Value']) log.debug('Number of perfSONAR endpoints: %s' % len(endpointList)) log.debug('End function.') return S_OK(endpointList) def __preparePerfSONARConfiguration(self, endpointList): """ Prepare a dictionary with a new CS configuration of perfSONAR endpoints. :return: Dictionary where keys are configuration paths (options and sections) and values are values of corresponding options or None in case of a path pointing to a section. """ log = self.log.getSubLogger('__preparePerfSONARConfiguration') log.debug('Begin function ...') # static elements of a path rootPath = '/Resources/Sites' extPath = 'Network' baseOptionName = 'Enabled' options = {baseOptionName: 'True', 'ServiceType': 'perfSONAR'} # enable GOCDB endpoints in configuration newConfiguration = {} for endpoint in endpointList: if endpoint['DIRACSITENAME'] is None: continue split = endpoint['DIRACSITENAME'].split('.') path = cfgPath(rootPath, split[0], endpoint['DIRACSITENAME'], extPath, endpoint['HOSTNAME']) for name, defaultValue in options.iteritems(): newConfiguration[cfgPath(path, name)] = defaultValue # get current configuration currentConfiguration = {} for option in options.iterkeys(): result = gConfig.getConfigurationTree(rootPath, extPath + '/', '/' + option) if not result['OK']: log.error("getConfigurationTree() failed with message: %s" % result['Message']) return S_ERROR('Unable to fetch perfSONAR endpoints from CS.') currentConfiguration.update(result['Value']) # disable endpoints that disappeared in GOCDB removedElements = set(currentConfiguration) - set(newConfiguration) newElements = set(newConfiguration) - set(currentConfiguration) addedEndpoints = len(newElements) / len(options) disabledEndpoints = 0 for path in removedElements: if baseOptionName in path: newConfiguration[path] = 'False' if currentConfiguration[path] != 'False': disabledEndpoints = disabledEndpoints + 1 # inform what will be changed if addedEndpoints > 0: self.log.info( "%s new perfSONAR endpoints will be added to the configuration" % addedEndpoints) if disabledEndpoints > 0: self.log.info( "%s old perfSONAR endpoints will be disable in the configuration" % disabledEndpoints) if addedEndpoints == 0 and disabledEndpoints == 0: self.log.info("perfSONAR configuration is up-to-date") log.debug('End function.') return S_OK(newConfiguration) def __addDIRACSiteName(self, inputList): """ Extend given list of GOCDB endpoints with DIRAC site name, i.e. add an entry "DIRACSITENAME" in dictionaries that describe endpoints. If given site name could not be found "DIRACSITENAME" is set to 'None'. :return: List of perfSONAR endpoints (dictionaries). """ log = self.log.getSubLogger('__addDIRACSiteName') log.debug('Begin function ...') # get site name dictionary result = getDIRACGOCDictionary() if not result['OK']: log.error("getDIRACGOCDictionary() failed with message: %s" % result['Message']) return S_ERROR('Could not get site name dictionary') # reverse the dictionary (assume 1 to 1 relation) DIRACGOCDict = result['Value'] GOCDIRACDict = dict(zip(DIRACGOCDict.values(), DIRACGOCDict.keys())) # add DIRAC site names outputList = [] for entry in inputList: try: entry['DIRACSITENAME'] = GOCDIRACDict[entry['SITENAME']] except KeyError: self.log.warn("No dictionary entry for %s. " % entry['SITENAME']) entry['DIRACSITENAME'] = None outputList.append(entry) log.debug('End function.') return S_OK(outputList) def __updateConfiguration(self, setElements=None, delElements=None): """ Update configuration stored by CS. """ if setElements is None: setElements = {} if delElements is None: delElements = [] log = self.log.getSubLogger('__updateConfiguration') log.debug('Begin function ...') # assure existence and proper value of a section or an option for path, value in setElements.iteritems(): if value is None: section = path else: split = path.rsplit('/', 1) section = split[0] try: result = self.csAPI.createSection(section) if not result['OK']: log.error("createSection() failed with message: %s" % result['Message']) except Exception as e: log.error("Exception in createSection(): %s" % repr(e).replace(',)', ')')) if value is not None: try: result = self.csAPI.setOption(path, value) if not result['OK']: log.error("setOption() failed with message: %s" % result['Message']) except Exception as e: log.error("Exception in setOption(): %s" % repr(e).replace(',)', ')')) # delete elements in the configuration for path in delElements: result = self.csAPI.delOption(path) if not result['OK']: log.warn("delOption() failed with message: %s" % result['Message']) result = self.csAPI.delSection(path) if not result['OK']: log.warn("delSection() failed with message: %s" % result['Message']) if self.dryRun: log.info("Dry Run: CS won't be updated") self.csAPI.showDiff() else: # update configuration stored by CS result = self.csAPI.commit() if not result['OK']: log.error("commit() failed with message: %s" % result['Message']) return S_ERROR("Could not commit changes to CS.") else: log.info("Committed changes to CS") log.debug('End function.') return S_OK() # define mapping between an agent option in the configuration and a function call __functionMap = { 'UpdatePerfSONARS': updatePerfSONARConfiguration, }
class Bdii2CSAgent(AgentModule): def __init__(self, *args, **kwargs): """ Defines default parameters """ super(Bdii2CSAgent, self).__init__(*args, **kwargs) self.addressTo = '' self.addressFrom = '' self.voName = [] self.subject = "Bdii2CSAgent" self.alternativeBDIIs = [] self.voBdiiCEDict = {} self.voBdiiSEDict = {} self.csAPI = None # What to get self.processCEs = True self.processSEs = False # Update the CS or not? self.dryRun = False def initialize(self): """ Gets run paramaters from the configuration """ self.addressTo = self.am_getOption('MailTo', self.addressTo) self.addressFrom = self.am_getOption('MailFrom', self.addressFrom) # Create a list of alternative bdii urls self.alternativeBDIIs = self.am_getOption('AlternativeBDIIs', self.alternativeBDIIs) # Check if the bdii url is appended by a port number, if not append the default 2170 for index, url in enumerate(self.alternativeBDIIs): if not url.split(':')[-1].isdigit(): self.alternativeBDIIs[index] += ':2170' if self.addressTo and self.addressFrom: self.log.info("MailTo", self.addressTo) self.log.info("MailFrom", self.addressFrom) if self.alternativeBDIIs: self.log.info("AlternativeBDII URLs:", self.alternativeBDIIs) self.processCEs = self.am_getOption('ProcessCEs', self.processCEs) self.processSEs = self.am_getOption('ProcessSEs', self.processSEs) self.dryRun = self.am_getOption('DryRun', self.dryRun) self.voName = self.am_getOption('VirtualOrganization', self.voName) if not self.voName: self.voName = self.am_getOption('VO', []) if not self.voName or (len(self.voName) == 1 and self.voName[0].lower() == 'all'): # Get all VOs defined in the configuration self.voName = [] result = getVOs() if result['OK']: vos = result['Value'] for vo in vos: vomsVO = getVOOption(vo, "VOMSName") if vomsVO: self.voName.append(vomsVO) if self.voName: self.log.info("Agent will manage VO(s) %s" % self.voName) else: self.log.fatal("VirtualOrganization option not defined for agent") return S_ERROR() self.csAPI = CSAPI() return self.csAPI.initialize() def execute(self): """ General agent execution method """ self.voBdiiCEDict = {} self.voBdiiSEDict = {} # Get a "fresh" copy of the CS data result = self.csAPI.downloadCSData() if not result['OK']: self.log.warn("Could not download a fresh copy of the CS data", result['Message']) # Refresh the configuration from the master server gConfig.forceRefresh(fromMaster=True) if self.processCEs: self.__lookForNewCEs() self.__updateCEs() if self.processSEs: self.__lookForNewSEs() self.__updateSEs() return S_OK() def __lookForNewCEs(self): """ Look up BDII for CEs not yet present in the DIRAC CS """ bannedCEs = self.am_getOption('BannedCEs', []) result = getCEsFromCS() if not result['OK']: return result knownCEs = set(result['Value']) knownCEs = knownCEs.union(set(bannedCEs)) for vo in self.voName: result = self.__getBdiiCEInfo(vo) if not result['OK']: continue bdiiInfo = result['Value'] result = getGridCEs(vo, bdiiInfo=bdiiInfo, ceBlackList=knownCEs) if not result['OK']: self.log.error('Failed to get unused CEs', result['Message']) siteDict = result['Value'] body = '' for site in siteDict: newCEs = set(siteDict[site].keys()) if not newCEs: continue ceString = '' for ce in newCEs: queueString = '' ceInfo = bdiiInfo[site]['CEs'][ce] newCEString = "CE: %s, GOCDB Site Name: %s" % (ce, site) systemTuple = siteDict[site][ce]['System'] osString = "%s_%s_%s" % (systemTuple) newCEString = "\n%s\n%s\n" % (newCEString, osString) for queue in ceInfo['Queues']: queueStatus = ceInfo['Queues'][queue].get( 'GlueCEStateStatus', 'UnknownStatus') if 'production' in queueStatus.lower(): ceType = ceInfo['Queues'][queue].get( 'GlueCEImplementationName', '') queueString += " %s %s %s\n" % ( queue, queueStatus, ceType) if queueString: ceString += newCEString ceString += "Queues:\n" ceString += queueString if ceString: body += ceString if body: body = "\nWe are glad to inform You about new CE(s) possibly suitable for %s:\n" % vo + body body += "\n\nTo suppress information about CE add its name to BannedCEs list.\n" body += "Add new Sites/CEs for vo %s with the command:\n" % vo body += "dirac-admin-add-resources --vo %s --ce\n" % vo self.log.info(body) if self.addressTo and self.addressFrom: notification = NotificationClient() result = notification.sendMail(self.addressTo, self.subject, body, self.addressFrom, localAttempt=False) if not result['OK']: self.log.error( 'Can not send new site notification mail', result['Message']) return S_OK() def __getBdiiCEInfo(self, vo): if vo in self.voBdiiCEDict: return S_OK(self.voBdiiCEDict[vo]) self.log.info("Check for available CEs for VO", vo) totalResult = S_OK({}) message = '' mainResult = getBdiiCEInfo(vo) if not mainResult['OK']: self.log.error("Failed getting information from default bdii", mainResult['Message']) message = mainResult['Message'] for bdii in reversed(self.alternativeBDIIs): resultAlt = getBdiiCEInfo(vo, host=bdii) if resultAlt['OK']: totalResult['Value'].update(resultAlt['Value']) else: self.log.error("Failed getting information from %s " % bdii, resultAlt['Message']) message = (message + "\n" + resultAlt['Message']).strip() if mainResult['OK']: totalResult['Value'].update(mainResult['Value']) if not totalResult[ 'Value'] and message: ## Dict is empty and we have an error message self.log.error("Error during BDII request", message) totalResult = S_ERROR(message) else: self.voBdiiCEDict[vo] = totalResult['Value'] return totalResult def __getBdiiSEInfo(self, vo): if vo in self.voBdiiSEDict: return S_OK(self.voBdiiSEDict[vo]) self.log.info("Check for available SEs for VO", vo) result = getBdiiSEInfo(vo) message = '' if not result['OK']: message = result['Message'] for bdii in self.alternativeBDIIs: result = getBdiiSEInfo(vo, host=bdii) if result['OK']: break if not result['OK']: if message: self.log.error("Error during BDII request", message) else: self.log.error("Error during BDII request", result['Message']) else: self.voBdiiSEDict[vo] = result['Value'] return result def __updateCEs(self): """ Update the Site/CE/queue settings in the CS if they were changed in the BDII """ bdiiChangeSet = set() for vo in self.voName: result = self.__getBdiiCEInfo(vo) if not result['OK']: continue ceBdiiDict = result['Value'] result = getSiteUpdates(vo, bdiiInfo=ceBdiiDict, log=self.log) if not result['OK']: continue bdiiChangeSet = bdiiChangeSet.union(result['Value']) # We have collected all the changes, consolidate VO settings result = self.__updateCS(bdiiChangeSet) return result def __updateCS(self, bdiiChangeSet): queueVODict = {} changeSet = set() for entry in bdiiChangeSet: section, option, _value, new_value = entry if option == "VO": queueVODict.setdefault(section, set()) queueVODict[section] = queueVODict[section].union( set(new_value.split(','))) else: changeSet.add(entry) for section, VOs in queueVODict.items(): changeSet.add((section, 'VO', '', ','.join(VOs))) if changeSet: changeList = list(changeSet) changeList.sort() body = '\n'.join( ["%s/%s %s -> %s" % entry for entry in changeList]) if body and self.addressTo and self.addressFrom: notification = NotificationClient() result = notification.sendMail(self.addressTo, self.subject, body, self.addressFrom, localAttempt=False) if body: self.log.info( 'The following configuration changes were detected:') self.log.info(body) for section, option, value, new_value in changeSet: if value == 'Unknown' or not value: self.csAPI.setOption(cfgPath(section, option), new_value) else: self.csAPI.modifyValue(cfgPath(section, option), new_value) if self.dryRun: self.log.info("Dry Run: CS won't be updated") self.csAPI.showDiff() else: result = self.csAPI.commit() if not result['OK']: self.log.error("Error while committing to CS", result['Message']) else: self.log.info("Successfully committed %d changes to CS" % len(changeList)) return result else: self.log.info("No changes found") return S_OK() def __lookForNewSEs(self): """ Look up BDII for SEs not yet present in the DIRAC CS """ bannedSEs = self.am_getOption('BannedSEs', []) result = getSEsFromCS() if not result['OK']: return result knownSEs = set(result['Value']) knownSEs = knownSEs.union(set(bannedSEs)) for vo in self.voName: result = self.__getBdiiSEInfo(vo) if not result['OK']: continue bdiiInfo = result['Value'] result = getGridSRMs(vo, bdiiInfo=bdiiInfo, srmBlackList=knownSEs) if not result['OK']: continue siteDict = result['Value'] body = '' for site in siteDict: newSEs = set(siteDict[site].keys()) if not newSEs: continue for se in newSEs: body += '\n New SE %s available at site %s:\n' % (se, site) backend = siteDict[site][se]['SE'].get( 'GlueSEImplementationName', 'Unknown') size = siteDict[site][se]['SE'].get( 'GlueSESizeTotal', 'Unknown') body += ' Backend %s, Size %s' % (backend, size) if body: body = "\nWe are glad to inform You about new SE(s) possibly suitable for %s:\n" % vo + body body += "\n\nTo suppress information about an SE add its name to BannedSEs list.\n" body += "Add new SEs for vo %s with the command:\n" % vo body += "dirac-admin-add-resources --vo %s --se\n" % vo self.log.info(body) if self.addressTo and self.addressFrom: notification = NotificationClient() result = notification.sendMail(self.addressTo, self.subject, body, self.addressFrom, localAttempt=False) if not result['OK']: self.log.error( 'Can not send new site notification mail', result['Message']) return S_OK() def __updateSEs(self): """ Update the Storage Element settings in the CS if they were changed in the BDII """ bdiiChangeSet = set() for vo in self.voName: result = self.__getBdiiSEInfo(vo) if not result['OK']: continue seBdiiDict = result['Value'] result = getSRMUpdates(vo, bdiiInfo=seBdiiDict) if not result['OK']: continue bdiiChangeSet = bdiiChangeSet.union(result['Value']) # We have collected all the changes, consolidate VO settings result = self.__updateCS(bdiiChangeSet) return result
def checkUnusedSEs(): global vo, dry result = getGridSRMs( vo, unUsed = True ) if not result['OK']: gLogger.error( 'Failed to look up SRMs in BDII', result['Message'] ) siteSRMDict = result['Value'] # Evaluate VOs result = getVOs() if result['OK']: csVOs = set( result['Value'] ) else: csVOs = {vo} changeSetFull = set() for site in siteSRMDict: for gridSE in siteSRMDict[site]: changeSet = set() seDict = siteSRMDict[site][gridSE]['SE'] srmDict = siteSRMDict[site][gridSE]['SRM'] # Check the SRM version version = srmDict.get( 'GlueServiceVersion', '' ) if not ( version and version.startswith( '2' ) ): gLogger.debug( 'Skipping SRM service with version %s' % version ) continue result = getDIRACSiteName( site ) if not result['OK']: gLogger.notice( 'Unused se %s is detected at unused site %s' % ( gridSE, site ) ) gLogger.notice( 'Consider adding site %s to the DIRAC CS' % site ) continue diracSites = result['Value'] yn = raw_input( '\nDo you want to add new SRM SE %s at site(s) %s ? default yes [yes|no]: ' % ( gridSE, str( diracSites ) ) ) if not yn or yn.lower().startswith( 'y' ): if len( diracSites ) > 1: prompt = 'Which DIRAC site the new SE should be attached to ?' for i, s in enumerate( diracSites ): prompt += '\n[%d] %s' % ( i, s ) prompt += '\nEnter your choice number: ' inp = raw_input( prompt ) try: ind = int( inp ) except: gLogger.notice( 'Can not interpret your choice: %s, try again later' % inp ) continue diracSite = diracSites[ind] else: diracSite = diracSites[0] domain, siteName, country = diracSite.split( '.' ) recName = '%s-disk' % siteName inp = raw_input( 'Give a DIRAC name to the grid SE %s, default %s : ' % ( gridSE, recName ) ) diracSEName = inp if not inp: diracSEName = recName gLogger.notice( 'Adding new SE %s at site %s' % ( diracSEName, diracSite ) ) seSection = cfgPath( '/Resources/StorageElements', diracSEName ) changeSet.add( ( seSection, 'BackendType', seDict.get( 'GlueSEImplementationName', 'Unknown' ) ) ) changeSet.add( ( seSection, 'Description', seDict.get( 'GlueSEName', 'Unknown' ) ) ) bdiiVOs = set( [ re.sub( '^VO:', '', rule ) for rule in srmDict.get( 'GlueServiceAccessControlBaseRule', [] ) ] ) seVOs = csVOs.intersection( bdiiVOs ) changeSet.add( ( seSection, 'VO', ','.join( seVOs ) ) ) accessSection = cfgPath( seSection, 'AccessProtocol.1' ) changeSet.add( ( accessSection, 'Protocol', 'srm' ) ) changeSet.add( ( accessSection, 'PluginName', 'SRM2' ) ) endPoint = srmDict.get( 'GlueServiceEndpoint', '' ) host = urlparse( endPoint ).hostname port = urlparse( endPoint ).port changeSet.add( ( accessSection, 'Host', host ) ) changeSet.add( ( accessSection, 'Port', port ) ) changeSet.add( ( accessSection, 'Access', 'remote' ) ) voPathSection = cfgPath( accessSection, 'VOPath' ) if 'VOPath' in seDict: path = seDict['VOPath'] voFromPath = os.path.basename( path ) if voFromPath != diracVO: gLogger.notice( '\n!!! Warning: non-conventional VO path: %s\n' % path ) changeSet.add( ( voPathSection, diracVO, path ) ) path = os.path.dirname( path ) else: # Try to guess the Path domain = '.'.join( host.split( '.' )[-2:] ) path = '/dpm/%s/home' % domain changeSet.add( ( accessSection, 'Path', path ) ) changeSet.add( ( accessSection, 'SpaceToken', '' ) ) changeSet.add( ( accessSection, 'WSUrl', '/srm/managerv2?SFN=' ) ) gLogger.notice( 'SE %s will be added with the following parameters' % diracSEName ) changeList = list( changeSet ) changeList.sort() for entry in changeList: gLogger.notice( entry ) yn = raw_input( 'Do you want to add new SE %s ? default yes [yes|no]: ' % diracSEName ) if not yn or yn.lower().startswith( 'y' ): changeSetFull = changeSetFull.union( changeSet ) if dry: if changeSetFull: gLogger.notice( 'Skipping commit of the new SE data in a dry run' ) else: gLogger.notice( "No new SE to be added" ) return S_OK() if changeSetFull: csAPI = CSAPI() csAPI.initialize() result = csAPI.downloadCSData() if not result['OK']: gLogger.error( 'Failed to initialize CSAPI object', result['Message'] ) DIRACExit( -1 ) changeList = list( changeSetFull ) changeList.sort() for section, option, value in changeList: csAPI.setOption( cfgPath( section, option ), value ) yn = raw_input( 'New SE data is accumulated\n Do you want to commit changes to CS ? default yes [yes|no]: ' ) if not yn or yn.lower().startswith( 'y' ): result = csAPI.commit() if not result['OK']: gLogger.error( "Error while commit to CS", result['Message'] ) else: gLogger.notice( "Successfully committed %d changes to CS" % len( changeSetFull ) ) else: gLogger.notice( "No new SE to be added" ) return S_OK()
# { # DBName = FileCatalogDB # } # } # } # } from DIRAC.ConfigurationSystem.Client.CSAPI import CSAPI csAPI = CSAPI() for sct in [ 'Systems/DataManagement', 'Systems/DataManagement/Production', 'Systems/DataManagement/Production/Databases', 'Systems/DataManagement/Production/Databases/FileCatalogDB' ]: res = csAPI.createSection(sct) if not res['OK']: print res['Message'] exit(1) csAPI.setOption( 'Systems/DataManagement/Production/Databases/FileCatalogDB/DBName', 'FileCatalogDB') csAPI.setOption( 'Systems/DataManagement/Production/Databases/FileCatalogDB/Host', 'db-50098.cern.ch') csAPI.setOption( 'Systems/DataManagement/Production/Databases/FileCatalogDB/Port', '5501') csAPI.commit()
class DiracAdmin(API): """ Administrative functionalities """ ############################################################################# def __init__(self): """Internal initialization of the DIRAC Admin API. """ super(DiracAdmin, self).__init__() self.csAPI = CSAPI() self.dbg = False if gConfig.getValue(self.section + '/LogLevel', 'DEBUG') == 'DEBUG': self.dbg = True self.scratchDir = gConfig.getValue(self.section + '/ScratchDir', '/tmp') self.currentDir = os.getcwd() ############################################################################# def uploadProxy(self, group): """Upload a proxy to the DIRAC WMS. This method Example usage: >>> print diracAdmin.uploadProxy('lhcb_pilot') {'OK': True, 'Value': 0L} :param group: DIRAC Group :type job: string :return: S_OK,S_ERROR :param permanent: Indefinitely update proxy :type permanent: boolean """ return gProxyManager.uploadProxy(diracGroup=group) ############################################################################# def setProxyPersistency(self, userDN, userGroup, persistent=True): """Set the persistence of a proxy in the Proxy Manager Example usage: >>> print diracAdmin.setProxyPersistency( 'some DN', 'dirac group', True ) {'OK': True } :param userDN: User DN :type userDN: string :param userGroup: DIRAC Group :type userGroup: string :param persistent: Persistent flag :type persistent: boolean :return: S_OK,S_ERROR """ return gProxyManager.setPersistency(userDN, userGroup, persistent) ############################################################################# def checkProxyUploaded(self, userDN, userGroup, requiredTime): """Set the persistence of a proxy in the Proxy Manager Example usage: >>> print diracAdmin.setProxyPersistency( 'some DN', 'dirac group', True ) {'OK': True, 'Value' : True/False } :param userDN: User DN :type userDN: string :param userGroup: DIRAC Group :type userGroup: string :param requiredTime: Required life time of the uploaded proxy :type requiredTime: boolean :return: S_OK,S_ERROR """ return gProxyManager.userHasProxy(userDN, userGroup, requiredTime) ############################################################################# def getSiteMask(self, printOutput=False): """Retrieve current site mask from WMS Administrator service. Example usage: >>> print diracAdmin.getSiteMask() {'OK': True, 'Value': 0L} :return: S_OK,S_ERROR """ wmsAdmin = RPCClient('WorkloadManagement/WMSAdministrator') result = wmsAdmin.getSiteMask() if result['OK']: sites = result['Value'] if printOutput: sites.sort() for site in sites: print site return result ############################################################################# def getBannedSites(self, gridType=[], printOutput=False): """Retrieve current list of banned sites. Example usage: >>> print diracAdmin.getBannedSites() {'OK': True, 'Value': []} :return: S_OK,S_ERROR """ wmsAdmin = RPCClient('WorkloadManagement/WMSAdministrator') bannedSites = [] totalList = [] result = wmsAdmin.getSiteMask() if not result['OK']: self.log.warn(result['Message']) return result sites = result['Value'] if not gridType: result = gConfig.getSections('/Resources/Sites') if not result['OK']: return result gridType = result['Value'] for grid in gridType: result = gConfig.getSections('/Resources/Sites/%s' % grid) if not result['OK']: return result totalList += result['Value'] for site in totalList: if not site in sites: bannedSites.append(site) bannedSites.sort() if printOutput: print '\n'.join(bannedSites) return S_OK(bannedSites) ############################################################################# def getSiteSection(self, site, printOutput=False): """Simple utility to get the list of CEs for DIRAC site name. Example usage: >>> print diracAdmin.getSiteSection('LCG.CERN.ch') {'OK': True, 'Value':} :return: S_OK,S_ERROR """ gridType = site.split('.')[0] if not gConfig.getSections('/Resources/Sites/%s' % (gridType))['OK']: return S_ERROR('/Resources/Sites/%s is not a valid site section' % (gridType)) result = gConfig.getOptionsDict('/Resources/Sites/%s/%s' % (gridType, site)) if printOutput and result['OK']: print self.pPrint.pformat(result['Value']) return result ############################################################################# def addSiteInMask(self, site, comment, printOutput=False): """Adds the site to the site mask. Example usage: >>> print diracAdmin.addSiteInMask() {'OK': True, 'Value': } :return: S_OK,S_ERROR """ result = self.__checkSiteIsValid(site) if not result['OK']: return result mask = self.getSiteMask() if not mask['OK']: return mask siteMask = mask['Value'] if site in siteMask: return S_ERROR('Site %s already in mask of allowed sites' % site) wmsAdmin = RPCClient('WorkloadManagement/WMSAdministrator') result = wmsAdmin.allowSite(site, comment) if not result['OK']: return result if printOutput: print 'Allowing %s in site mask' % site return result ############################################################################# def getSiteMaskLogging(self, site=None, printOutput=False): """Retrieves site mask logging information. Example usage: >>> print diracAdmin.getSiteMaskLogging('LCG.AUVER.fr') {'OK': True, 'Value': } :return: S_OK,S_ERROR """ result = self.__checkSiteIsValid(site) if not result['OK']: return result wmsAdmin = RPCClient('WorkloadManagement/WMSAdministrator') result = wmsAdmin.getSiteMaskLogging(site) if not result['OK']: return result if site: if not result['Value'].has_key(site): return S_ERROR('Site mask information not available for %s' % (site)) if printOutput: if site: print '\nSite Mask Logging Info for %s\n' % site else: print '\nAll Site Mask Logging Info\n' siteDict = result['Value'] for site, tupleList in siteDict.iteritems(): if not site: print '\n===> %s\n' % site for tup in tupleList: print str( tup[0] ).ljust( 8 ) + str( tup[1] ).ljust( 20 ) + \ '( ' + str( tup[2] ).ljust( len( str( tup[2] ) ) ) + ' ) "' + str( tup[3] ) + '"' print ' ' return result ############################################################################# def banSiteFromMask(self, site, comment, printOutput=False): """Removes the site from the site mask. Example usage: >>> print diracAdmin.banSiteFromMask() {'OK': True, 'Value': } :return: S_OK,S_ERROR """ result = self.__checkSiteIsValid(site) if not result['OK']: return result mask = self.getSiteMask() if not mask['OK']: return mask siteMask = mask['Value'] if not site in siteMask: return S_ERROR('Site %s is already banned' % site) wmsAdmin = RPCClient('WorkloadManagement/WMSAdministrator') result = wmsAdmin.banSite(site, comment) if not result['OK']: return result if printOutput: print 'Removing %s from site mask' % site return result ############################################################################# @classmethod def __checkSiteIsValid(self, site): """Internal function to check that a site name is valid. """ sites = getSiteCEMapping() if not sites['OK']: return S_ERROR('Could not get site CE mapping') siteList = sites['Value'].keys() if not site in siteList: return S_ERROR( 'Specified site %s is not in list of defined sites' % site) return S_OK('%s is valid' % site) ############################################################################# def clearMask(self): """Removes all sites from the site mask. Should be used with care. Example usage: >>> print diracAdmin.clearMask() {'OK': True, 'Value':''} :return: S_OK,S_ERROR """ wmsAdmin = RPCClient('WorkloadManagement/WMSAdministrator') result = wmsAdmin.clearMask() return result ############################################################################# def getServicePorts(self, setup='', printOutput=False): """Checks the service ports for the specified setup. If not given this is taken from the current installation (/DIRAC/Setup) Example usage: >>> print diracAdmin.getServicePorts() {'OK': True, 'Value':''} :return: S_OK,S_ERROR """ if not setup: setup = gConfig.getValue('/DIRAC/Setup', '') setupList = gConfig.getSections('/DIRAC/Setups', []) if not setupList['OK']: return S_ERROR('Could not get /DIRAC/Setups sections') setupList = setupList['Value'] if not setup in setupList: return S_ERROR('Setup %s is not in allowed list: %s' % (setup, ', '.join(setupList))) serviceSetups = gConfig.getOptionsDict('/DIRAC/Setups/%s' % setup) if not serviceSetups['OK']: return S_ERROR('Could not get /DIRAC/Setups/%s options' % setup) serviceSetups = serviceSetups['Value'] # dict systemList = gConfig.getSections('/Systems') if not systemList['OK']: return S_ERROR('Could not get Systems sections') systemList = systemList['Value'] result = {} for system in systemList: if serviceSetups.has_key(system): path = '/Systems/%s/%s/Services' % (system, serviceSetups[system]) servicesList = gConfig.getSections(path) if not servicesList['OK']: self.log.warn('Could not get sections in %s' % path) else: servicesList = servicesList['Value'] if not servicesList: servicesList = [] self.log.verbose('System: %s ServicesList: %s' % (system, ', '.join(servicesList))) for service in servicesList: spath = '%s/%s/Port' % (path, service) servicePort = gConfig.getValue(spath, 0) if servicePort: self.log.verbose('Found port for %s/%s = %s' % (system, service, servicePort)) result['%s/%s' % (system, service)] = servicePort else: self.log.warn('No port found for %s' % spath) else: self.log.warn('%s is not defined in /DIRAC/Setups/%s' % (system, setup)) if printOutput: print self.pPrint.pformat(result) return S_OK(result) ############################################################################# def getProxy(self, userDN, userGroup, validity=43200, limited=False): """Retrieves a proxy with default 12hr validity and stores this in a file in the local directory by default. Example usage: >>> print diracAdmin.getProxy() {'OK': True, 'Value': } :return: S_OK,S_ERROR """ return gProxyManager.downloadProxy(userDN, userGroup, limited=limited, requiredTimeLeft=validity) ############################################################################# def getVOMSProxy(self, userDN, userGroup, vomsAttr=False, validity=43200, limited=False): """Retrieves a proxy with default 12hr validity and VOMS extensions and stores this in a file in the local directory by default. Example usage: >>> print diracAdmin.getVOMSProxy() {'OK': True, 'Value': } :return: S_OK,S_ERROR """ return gProxyManager.downloadVOMSProxy(userDN, userGroup, limited=limited, requiredVOMSAttribute=vomsAttr, requiredTimeLeft=validity) ############################################################################# def getPilotProxy(self, userDN, userGroup, validity=43200): """Retrieves a pilot proxy with default 12hr validity and stores this in a file in the local directory by default. Example usage: >>> print diracAdmin.getVOMSProxy() {'OK': True, 'Value': } :return: S_OK,S_ERROR """ return gProxyManager.getPilotProxyFromDIRACGroup( userDN, userGroup, requiredTimeLeft=validity) ############################################################################# def resetJob(self, jobID): """Reset a job or list of jobs in the WMS. This operation resets the reschedule counter for a job or list of jobs and allows them to run as new. Example:: >>> print dirac.reset(12345) {'OK': True, 'Value': [12345]} :param job: JobID :type job: integer or list of integers :return: S_OK,S_ERROR """ if isinstance(jobID, basestring): try: jobID = int(jobID) except Exception as x: return self._errorReport( str(x), 'Expected integer or convertible integer for existing jobID' ) elif isinstance(jobID, list): try: jobID = [int(job) for job in jobID] except Exception as x: return self._errorReport( str(x), 'Expected integer or convertible integer for existing jobIDs' ) jobManager = RPCClient('WorkloadManagement/JobManager', useCertificates=False) result = jobManager.resetJob(jobID) return result ############################################################################# def getJobPilotOutput(self, jobID, directory=''): """Retrieve the pilot output for an existing job in the WMS. The output will be retrieved in a local directory unless otherwise specified. >>> print dirac.getJobPilotOutput(12345) {'OK': True, StdOut:'',StdError:''} :param job: JobID :type job: integer or string :return: S_OK,S_ERROR """ if not directory: directory = self.currentDir if not os.path.exists(directory): return self._errorReport('Directory %s does not exist' % directory) wmsAdmin = RPCClient('WorkloadManagement/WMSAdministrator') result = wmsAdmin.getJobPilotOutput(jobID) if not result['OK']: return result outputPath = '%s/pilot_%s' % (directory, jobID) if os.path.exists(outputPath): self.log.info('Remove %s and retry to continue' % outputPath) return S_ERROR('Remove %s and retry to continue' % outputPath) if not os.path.exists(outputPath): self.log.verbose('Creating directory %s' % outputPath) os.mkdir(outputPath) outputs = result['Value'] if outputs.has_key('StdOut'): stdout = '%s/std.out' % (outputPath) with open(stdout, 'w') as fopen: fopen.write(outputs['StdOut']) self.log.verbose('Standard output written to %s' % (stdout)) else: self.log.warn('No standard output returned') if outputs.has_key('StdError'): stderr = '%s/std.err' % (outputPath) with open(stderr, 'w') as fopen: fopen.write(outputs['StdError']) self.log.verbose('Standard error written to %s' % (stderr)) else: self.log.warn('No standard error returned') self.log.always('Outputs retrieved in %s' % outputPath) return result ############################################################################# def getPilotOutput(self, gridReference, directory=''): """Retrieve the pilot output (std.out and std.err) for an existing job in the WMS. >>> print dirac.getJobPilotOutput(12345) {'OK': True, 'Value': {}} :param job: JobID :type job: integer or string :return: S_OK,S_ERROR """ if not isinstance(gridReference, basestring): return self._errorReport('Expected string for pilot reference') if not directory: directory = self.currentDir if not os.path.exists(directory): return self._errorReport('Directory %s does not exist' % directory) wmsAdmin = RPCClient('WorkloadManagement/WMSAdministrator') result = wmsAdmin.getPilotOutput(gridReference) if not result['OK']: return result gridReferenceSmall = gridReference.split('/')[-1] if not gridReferenceSmall: gridReferenceSmall = 'reference' outputPath = '%s/pilot_%s' % (directory, gridReferenceSmall) if os.path.exists(outputPath): self.log.info('Remove %s and retry to continue' % outputPath) return S_ERROR('Remove %s and retry to continue' % outputPath) if not os.path.exists(outputPath): self.log.verbose('Creating directory %s' % outputPath) os.mkdir(outputPath) outputs = result['Value'] if outputs.has_key('StdOut'): stdout = '%s/std.out' % (outputPath) with open(stdout, 'w') as fopen: fopen.write(outputs['StdOut']) self.log.info('Standard output written to %s' % (stdout)) else: self.log.warn('No standard output returned') if outputs.has_key('StdErr'): stderr = '%s/std.err' % (outputPath) with open(stderr, 'w') as fopen: fopen.write(outputs['StdErr']) self.log.info('Standard error written to %s' % (stderr)) else: self.log.warn('No standard error returned') self.log.always('Outputs retrieved in %s' % outputPath) return result ############################################################################# def getPilotInfo(self, gridReference): """Retrieve info relative to a pilot reference >>> print dirac.getPilotInfo(12345) {'OK': True, 'Value': {}} :param gridReference: Pilot Job Reference :type gridReference: string :return: S_OK,S_ERROR """ if not isinstance(gridReference, basestring): return self._errorReport('Expected string for pilot reference') wmsAdmin = RPCClient('WorkloadManagement/WMSAdministrator') result = wmsAdmin.getPilotInfo(gridReference) return result ############################################################################# def killPilot(self, gridReference): """Kill the pilot specified >>> print dirac.getPilotInfo(12345) {'OK': True, 'Value': {}} :param gridReference: Pilot Job Reference :return: S_OK,S_ERROR """ if not isinstance(gridReference, basestring): return self._errorReport('Expected string for pilot reference') wmsAdmin = RPCClient('WorkloadManagement/WMSAdministrator') result = wmsAdmin.killPilot(gridReference) return result ############################################################################# def getPilotLoggingInfo(self, gridReference): """Retrieve the pilot logging info for an existing job in the WMS. >>> print dirac.getPilotLoggingInfo(12345) {'OK': True, 'Value': {"The output of the command"}} :param gridReference: Gridp pilot job reference Id :type gridReference: string :return: S_OK,S_ERROR """ if type(gridReference) not in types.StringTypes: return self._errorReport('Expected string for pilot reference') wmsAdmin = RPCClient('WorkloadManagement/WMSAdministrator') return wmsAdmin.getPilotLoggingInfo(gridReference) ############################################################################# def getJobPilots(self, jobID): """Extract the list of submitted pilots and their status for a given jobID from the WMS. Useful information is printed to the screen. >>> print dirac.getJobPilots() {'OK': True, 'Value': {PilotID:{StatusDict}}} :param job: JobID :type job: integer or string :return: S_OK,S_ERROR """ if isinstance(jobID, basestring): try: jobID = int(jobID) except Exception as x: return self._errorReport( str(x), 'Expected integer or string for existing jobID') wmsAdmin = RPCClient('WorkloadManagement/WMSAdministrator') result = wmsAdmin.getPilots(jobID) if result['OK']: print self.pPrint.pformat(result['Value']) return result ############################################################################# def getPilotSummary(self, startDate='', endDate=''): """Retrieve the pilot output for an existing job in the WMS. Summary is printed at INFO level, full dictionary of results also returned. >>> print dirac.getPilotSummary() {'OK': True, 'Value': {CE:{Status:Count}}} :param job: JobID :type job: integer or string :return: S_OK,S_ERROR """ wmsAdmin = RPCClient('WorkloadManagement/WMSAdministrator') result = wmsAdmin.getPilotSummary(startDate, endDate) if not result['OK']: return result ceDict = result['Value'] headers = 'CE'.ljust(28) i = 0 for ce, summary in ceDict.iteritems(): states = summary.keys() if len(states) > i: i = len(states) for i in xrange(i): headers += 'Status'.ljust(12) + 'Count'.ljust(12) print headers for ce, summary in ceDict.iteritems(): line = ce.ljust(28) states = summary.keys() states.sort() for state in states: count = str(summary[state]) line += state.ljust(12) + count.ljust(12) print line return result ############################################################################# def selectRequests(self, jobID=None, requestID=None, requestName=None, requestType=None, status=None, operation=None, ownerDN=None, ownerGroup=None, requestStart=0, limit=100, printOutput=False): """Select requests from the request management system. A few notes on the selection criteria: - jobID is the WMS JobID for the request (if applicable) - requestID is assigned during submission of the request - requestName is the corresponding XML file name - requestType e.g. 'transfer' - status e.g. Done - operation e.g. replicateAndRegister - requestStart e.g. the first request to consider (start from 0 by default) - limit e.g. selection limit (default 100) >>> dirac.selectRequests(jobID='4894') {'OK': True, 'Value': [[<Requests>]]} """ options = { 'RequestID': requestID, 'RequestName': requestName, 'JobID': jobID, 'OwnerDN': ownerDN, 'OwnerGroup': ownerGroup, 'RequestType': requestType, 'Status': status, 'Operation': operation } conditions = {} for key, value in options.iteritems(): if value: try: conditions[key] = str(value) except Exception as x: return self._errorReport( str(x), 'Expected string for %s field' % key) try: requestStart = int(requestStart) limit = int(limit) except Exception as x: return self._errorReport(str(x), 'Expected integer for %s field' % limit) self.log.verbose('Will select requests with the following conditions') self.log.verbose(self.pPrint.pformat(conditions)) requestClient = RPCClient("RequestManagement/centralURL") result = requestClient.getRequestSummaryWeb(conditions, [], requestStart, limit) if not result['OK']: self.log.warn(result['Message']) return result requestIDs = result['Value'] conds = [] for key, value in conditions.iteritems(): if value: conds.append('%s = %s' % (key, value)) self.log.verbose( '%s request(s) selected with conditions %s and limit %s' % (len(requestIDs['Records']), ', '.join(conds), limit)) if printOutput: requests = [] if len(requestIDs['Records']) > limit: requestList = requestIDs['Records'] requests = requestList[:limit] else: requests = requestIDs['Records'] print '%s request(s) selected with conditions %s and limit %s' % ( len(requestIDs['Records']), ', '.join(conds), limit) print requestIDs['ParameterNames'] for request in requests: print request if not requestIDs: return S_ERROR('No requests selected for conditions: %s' % conditions) else: return result ############################################################################# def getRequestSummary(self, printOutput=False): """ Get a summary of the requests in the request DB. """ requestClient = RPCClient("RequestManagement/centralURL", timeout=120) result = requestClient.getDBSummary() if not result['OK']: self.log.warn(result['Message']) return result if printOutput: print self.pPrint.pformat(result['Value']) return result ############################################################################# def getExternalPackageVersions(self): """ Simple function that attempts to obtain the external versions for the local DIRAC installation (frequently needed for debugging purposes). """ gLogger.info( 'DIRAC version v%dr%d build %d' % (DIRAC.majorVersion, DIRAC.minorVersion, DIRAC.patchLevel)) try: import lcg_util infoStr = 'Using lcg_util from: \n%s' % lcg_util.__file__ gLogger.info(infoStr) infoStr = "The version of lcg_utils is %s" % lcg_util.lcg_util_version( ) gLogger.info(infoStr) except Exception as x: errStr = "SRM2Storage.__init__: Failed to import lcg_util: %s" % ( x) gLogger.exception(errStr) try: import gfalthr as gfal infoStr = "Using gfalthr from: \n%s" % gfal.__file__ gLogger.info(infoStr) infoStr = "The version of gfalthr is %s" % gfal.gfal_version() gLogger.info(infoStr) except Exception as x: errStr = "SRM2Storage.__init__: Failed to import gfalthr: %s." % ( x) gLogger.warn(errStr) try: import gfal infoStr = "Using gfal from: %s" % gfal.__file__ gLogger.info(infoStr) infoStr = "The version of gfal is %s" % gfal.gfal_version() gLogger.info(infoStr) except Exception as x: errStr = "SRM2Storage.__init__: Failed to import gfal: %s" % ( x) gLogger.exception(errStr) defaultProtocols = gConfig.getValue( '/Resources/StorageElements/DefaultProtocols', []) gLogger.info('Default list of protocols are: %s' % (', '.join(defaultProtocols))) return S_OK() ############################################################################# def getSiteProtocols(self, site, printOutput=False): """ Allows to check the defined protocols for each site SE. """ result = self.__checkSiteIsValid(site) if not result['OK']: return result siteSection = '/Resources/Sites/%s/%s/SE' % (site.split('.')[0], site) siteSEs = gConfig.getValue(siteSection, []) if not siteSEs: return S_ERROR('No SEs found for site %s in section %s' % (site, siteSection)) defaultProtocols = gConfig.getValue( '/Resources/StorageElements/DefaultProtocols', []) self.log.verbose('Default list of protocols are' ', '.join(defaultProtocols)) seInfo = {} siteSEs.sort() for se in siteSEs: sections = gConfig.getSections('/Resources/StorageElements/%s/' % (se)) if not sections['OK']: return sections for section in sections['Value']: if gConfig.getValue( '/Resources/StorageElements/%s/%s/ProtocolName' % (se, section), '') == 'SRM2': path = '/Resources/StorageElements/%s/%s/ProtocolsList' % ( se, section) seProtocols = gConfig.getValue(path, []) if not seProtocols: seProtocols = defaultProtocols seInfo[se] = seProtocols if printOutput: print '\nSummary of protocols for StorageElements at site %s' % site print '\nStorageElement'.ljust(30) + 'ProtocolsList'.ljust( 30) + '\n' for se, protocols in seInfo.iteritems(): print se.ljust(30) + ', '.join(protocols).ljust(30) return S_OK(seInfo) ############################################################################# def setSiteProtocols(self, site, protocolsList, printOutput=False): """ Allows to set the defined protocols for each SE for a given site. """ result = self.__checkSiteIsValid(site) if not result['OK']: return result siteSection = '/Resources/Sites/%s/%s/SE' % (site.split('.')[0], site) siteSEs = gConfig.getValue(siteSection, []) if not siteSEs: return S_ERROR('No SEs found for site %s in section %s' % (site, siteSection)) defaultProtocols = gConfig.getValue( '/Resources/StorageElements/DefaultProtocols', []) self.log.verbose('Default list of protocols are', ', '.join(defaultProtocols)) for protocol in protocolsList: if not protocol in defaultProtocols: return S_ERROR( 'Requested to set protocol %s in list but %s is not ' 'in default list of protocols:\n%s' % (protocol, protocol, ', '.join(defaultProtocols))) modifiedCS = False result = promptUser( 'Do you want to add the following default protocols:' ' %s for SE(s):\n%s' % (', '.join(protocolsList), ', '.join(siteSEs))) if not result['OK']: return result if result['Value'].lower() != 'y': self.log.always('No protocols will be added') return S_OK() for se in siteSEs: sections = gConfig.getSections('/Resources/StorageElements/%s/' % (se)) if not sections['OK']: return sections for section in sections['Value']: if gConfig.getValue( '/Resources/StorageElements/%s/%s/ProtocolName' % (se, section), '') == 'SRM2': path = '/Resources/StorageElements/%s/%s/ProtocolsList' % ( se, section) self.log.verbose('Setting %s to %s' % (path, ', '.join(protocolsList))) result = self.csSetOption(path, ', '.join(protocolsList)) if not result['OK']: return result modifiedCS = True if modifiedCS: result = self.csCommitChanges(False) if not result['OK']: return S_ERROR('CS Commit failed with message = %s' % (result['Message'])) else: if printOutput: print 'Successfully committed changes to CS' else: if printOutput: print 'No modifications to CS required' return S_OK() ############################################################################# def csSetOption(self, optionPath, optionValue): """ Function to modify an existing value in the CS. """ return self.csAPI.setOption(optionPath, optionValue) ############################################################################# def csSetOptionComment(self, optionPath, comment): """ Function to modify an existing value in the CS. """ return self.csAPI.setOptionComment(optionPath, comment) ############################################################################# def csModifyValue(self, optionPath, newValue): """ Function to modify an existing value in the CS. """ return self.csAPI.modifyValue(optionPath, newValue) ############################################################################# def csRegisterUser(self, username, properties): """ Registers a user in the CS. - username: Username of the user (easy;) - properties: Dict containing: - DN - groups : list/tuple of groups the user belongs to - <others> : More properties of the user, like mail """ return self.csAPI.addUser(username, properties) ############################################################################# def csDeleteUser(self, user): """ Deletes a user from the CS. Can take a list of users """ return self.csAPI.deleteUsers(user) ############################################################################# def csModifyUser(self, username, properties, createIfNonExistant=False): """ Modify a user in the CS. Takes the same params as in addUser and applies the changes """ return self.csAPI.modifyUser(username, properties, createIfNonExistant) ############################################################################# def csListUsers(self, group=False): """ Lists the users in the CS. If no group is specified return all users. """ return self.csAPI.listUsers(group) ############################################################################# def csDescribeUsers(self, mask=False): """ List users and their properties in the CS. If a mask is given, only users in the mask will be returned """ return self.csAPI.describeUsers(mask) ############################################################################# def csModifyGroup(self, groupname, properties, createIfNonExistant=False): """ Modify a user in the CS. Takes the same params as in addGroup and applies the changes """ return self.csAPI.modifyGroup(groupname, properties, createIfNonExistant) ############################################################################# def csListHosts(self): """ Lists the hosts in the CS """ return self.csAPI.listHosts() ############################################################################# def csDescribeHosts(self, mask=False): """ Gets extended info for the hosts in the CS """ return self.csAPI.describeHosts(mask) ############################################################################# def csModifyHost(self, hostname, properties, createIfNonExistant=False): """ Modify a host in the CS. Takes the same params as in addHost and applies the changes """ return self.csAPI.modifyHost(hostname, properties, createIfNonExistant) ############################################################################# def csListGroups(self): """ Lists groups in the CS """ return self.csAPI.listGroups() ############################################################################# def csDescribeGroups(self, mask=False): """ List groups and their properties in the CS. If a mask is given, only groups in the mask will be returned """ return self.csAPI.describeGroups(mask) ############################################################################# def csSyncUsersWithCFG(self, usersCFG): """ Synchronize users in cfg with its contents """ return self.csAPI.syncUsersWithCFG(usersCFG) ############################################################################# def csCommitChanges(self, sortUsers=True): """ Commit the changes in the CS """ return self.csAPI.commitChanges(sortUsers=False) ############################################################################# def sendMail(self, address, subject, body, fromAddress=None, localAttempt=True, html=False): """ Send mail to specified address with body. """ notification = NotificationClient() return notification.sendMail(address, subject, body, fromAddress, localAttempt, html) ############################################################################# def sendSMS(self, userName, body, fromAddress=None): """ Send mail to specified address with body. """ if len(body) > 160: return S_ERROR('Exceeded maximum SMS length of 160 characters') notification = NotificationClient() return notification.sendSMS(userName, body, fromAddress) ############################################################################# def getBDIISite(self, site, host=None): """ Get information about site from BDII at host """ return ldapSite(site, host=host) ############################################################################# def getBDIICluster(self, ce, host=None): """ Get information about ce from BDII at host """ return ldapCluster(ce, host=host) ############################################################################# def getBDIICE(self, ce, host=None): """ Get information about ce from BDII at host """ return ldapCE(ce, host=host) ############################################################################# def getBDIIService(self, ce, host=None): """ Get information about ce from BDII at host """ return ldapService(ce, host=host) ############################################################################# def getBDIICEState(self, ce, useVO=voName, host=None): """ Get information about ce state from BDII at host """ return ldapCEState(ce, useVO, host=host) ############################################################################# def getBDIICEVOView(self, ce, useVO=voName, host=None): """ Get information about ce voview from BDII at host """ return ldapCEVOView(ce, useVO, host=host) ############################################################################# def getBDIISE(self, site, useVO=voName, host=None): """ Get information about SA from BDII at host """ return ldapSE(site, useVO, host=host)
# } for sct in ['Systems/DataManagement', 'Systems/DataManagement/Production', 'Systems/DataManagement/Production/Databases', 'Systems/DataManagement/Production/Databases/FileCatalogDB']: res = csAPI.createSection(sct) if not res['OK']: print res['Message'] exit(1) dbHost = os.environ['DB_HOST'] dbPort = os.environ['DB_PORT'] csAPI.setOption('Systems/DataManagement/Production/Databases/FileCatalogDB/DBName', 'FileCatalogDB') csAPI.setOption('Systems/DataManagement/Production/Databases/FileCatalogDB/Host', dbHost) csAPI.setOption('Systems/DataManagement/Production/Databases/FileCatalogDB/Port', dbPort) # Setup other DBs (this is for LHCb - innocuous!) # # Bookkeeping # { # Production # { # Databases # { # BookkeepingDB # { # LHCbDIRACBookkeepingTNS = # LHCbDIRACBookkeepingUser =
ses.extend( res['Value']['SE'].replace( ' ', '' ).split( ',' ) ) if not ses: gLogger.error( "There were no SEs provided" ) DIRAC.exit() readAllowed = [] writeAllowed = [] storageCFGBase = "/Resources/StorageElements" for se in ses: res = gConfig.getOptionsDict( "%s/%s" % ( storageCFGBase, se ) ) if not res['OK']: gLogger.error( "Storage Element %s does not exist" % se ) continue existingOptions = res['Value'] if read and existingOptions['ReadAccess'] == "InActive": res = csAPI.setOption( "%s/%s/ReadAccess" % ( storageCFGBase, se ), "Active" ) if not res['OK']: gLogger.error( "Failed to update %s read access to Active" % se ) else: gLogger.debug( "Successfully updated %s read access to Active" % se ) readAllowed.append( se ) if write and existingOptions['WriteAccess'] == "InActive": res = csAPI.setOption( "%s/%s/WriteAccess" % ( storageCFGBase, se ), "Active" ) if not res['OK']: gLogger.error( "Failed to update %s write access to Active" % se ) else: gLogger.debug( "Successfully updated %s write access to Active" % se ) writeAllowed.append( se ) res = csAPI.commitChanges() if not res['OK']: gLogger.error( "Failed to commit changes to CS", res['Message'] )
class DiracAdmin(API): """ Administrative functionalities """ ############################################################################# def __init__(self): """Internal initialization of the DIRAC Admin API. """ super(DiracAdmin, self).__init__() self.csAPI = CSAPI() self.dbg = False if gConfig.getValue(self.section + '/LogLevel', 'DEBUG') == 'DEBUG': self.dbg = True self.scratchDir = gConfig.getValue(self.section + '/ScratchDir', '/tmp') self.currentDir = os.getcwd() self.rssFlag = ResourceStatus().rssFlag self.sitestatus = SiteStatus() self._siteSet = set(getSites().get('Value', [])) ############################################################################# def uploadProxy(self): """Upload a proxy to the DIRAC WMS. This method Example usage: >>> print diracAdmin.uploadProxy('dteam_pilot') {'OK': True, 'Value': 0L} :return: S_OK,S_ERROR :param permanent: Indefinitely update proxy :type permanent: boolean """ return gProxyManager.uploadProxy() ############################################################################# def setProxyPersistency(self, userDN, userGroup, persistent=True): """Set the persistence of a proxy in the Proxy Manager Example usage: >>> gLogger.notice(diracAdmin.setProxyPersistency( 'some DN', 'dirac group', True )) {'OK': True } :param userDN: User DN :type userDN: string :param userGroup: DIRAC Group :type userGroup: string :param persistent: Persistent flag :type persistent: boolean :return: S_OK,S_ERROR """ return gProxyManager.setPersistency(userDN, userGroup, persistent) ############################################################################# def checkProxyUploaded(self, userDN, userGroup, requiredTime): """Set the persistence of a proxy in the Proxy Manager Example usage: >>> gLogger.notice(diracAdmin.setProxyPersistency( 'some DN', 'dirac group', True )) {'OK': True, 'Value' : True/False } :param userDN: User DN :type userDN: string :param userGroup: DIRAC Group :type userGroup: string :param requiredTime: Required life time of the uploaded proxy :type requiredTime: boolean :return: S_OK,S_ERROR """ return gProxyManager.userHasProxy(userDN, userGroup, requiredTime) ############################################################################# def getSiteMask(self, printOutput=False, status='Active'): """Retrieve current site mask from WMS Administrator service. Example usage: >>> gLogger.notice(diracAdmin.getSiteMask()) {'OK': True, 'Value': 0L} :return: S_OK,S_ERROR """ result = self.sitestatus.getSites(siteState=status) if result['OK']: sites = result['Value'] if printOutput: sites.sort() for site in sites: gLogger.notice(site) return result ############################################################################# def getBannedSites(self, printOutput=False): """Retrieve current list of banned and probing sites. Example usage: >>> gLogger.notice(diracAdmin.getBannedSites()) {'OK': True, 'Value': []} :return: S_OK,S_ERROR """ bannedSites = self.sitestatus.getSites(siteState='Banned') if not bannedSites['OK']: return bannedSites probingSites = self.sitestatus.getSites(siteState='Probing') if not probingSites['OK']: return probingSites mergedList = sorted(bannedSites['Value'] + probingSites['Value']) if printOutput: gLogger.notice('\n'.join(mergedList)) return S_OK(mergedList) ############################################################################# def getSiteSection(self, site, printOutput=False): """Simple utility to get the list of CEs for DIRAC site name. Example usage: >>> gLogger.notice(diracAdmin.getSiteSection('LCG.CERN.ch')) {'OK': True, 'Value':} :return: S_OK,S_ERROR """ gridType = site.split('.')[0] if not gConfig.getSections('/Resources/Sites/%s' % (gridType))['OK']: return S_ERROR('/Resources/Sites/%s is not a valid site section' % (gridType)) result = gConfig.getOptionsDict('/Resources/Sites/%s/%s' % (gridType, site)) if printOutput and result['OK']: gLogger.notice(self.pPrint.pformat(result['Value'])) return result ############################################################################# def allowSite(self, site, comment, printOutput=False): """Adds the site to the site mask. Example usage: >>> gLogger.notice(diracAdmin.allowSite()) {'OK': True, 'Value': } :return: S_OK,S_ERROR """ result = self.__checkSiteIsValid(site) if not result['OK']: return result result = self.getSiteMask(status='Active') if not result['OK']: return result siteMask = result['Value'] if site in siteMask: if printOutput: gLogger.notice('Site %s is already Active' % site) return S_OK('Site %s is already Active' % site) if self.rssFlag: result = self.sitestatus.setSiteStatus(site, 'Active', comment) else: result = WMSAdministratorClient().allowSite(site, comment) if not result['OK']: return result if printOutput: gLogger.notice('Site %s status is set to Active' % site) return result ############################################################################# def getSiteMaskLogging(self, site=None, printOutput=False): """Retrieves site mask logging information. Example usage: >>> gLogger.notice(diracAdmin.getSiteMaskLogging('LCG.AUVER.fr')) {'OK': True, 'Value': } :return: S_OK,S_ERROR """ result = self.__checkSiteIsValid(site) if not result['OK']: return result if self.rssFlag: result = ResourceStatusClient().selectStatusElement('Site', 'History', name=site) else: result = WMSAdministratorClient().getSiteMaskLogging(site) if not result['OK']: return result if printOutput: if site: gLogger.notice('\nSite Mask Logging Info for %s\n' % site) else: gLogger.notice('\nAll Site Mask Logging Info\n') sitesLogging = result['Value'] if isinstance(sitesLogging, dict): for siteName, tupleList in sitesLogging.iteritems(): if not siteName: gLogger.notice('\n===> %s\n' % siteName) for tup in tupleList: stup = str(tup[0]).ljust(8) + str(tup[1]).ljust(20) stup += '( ' + str(tup[2]).ljust(len(str( tup[2]))) + ' ) "' + str(tup[3]) + '"' gLogger.notice(stup) gLogger.notice(' ') elif isinstance(sitesLogging, list): result = [(sl[1], sl[3], sl[4]) for sl in sitesLogging] return result ############################################################################# def banSite(self, site, comment, printOutput=False): """Removes the site from the site mask. Example usage: >>> gLogger.notice(diracAdmin.banSite()) {'OK': True, 'Value': } :return: S_OK,S_ERROR """ result = self.__checkSiteIsValid(site) if not result['OK']: return result mask = self.getSiteMask(status='Banned') if not mask['OK']: return mask siteMask = mask['Value'] if site in siteMask: if printOutput: gLogger.notice('Site %s is already Banned' % site) return S_OK('Site %s is already Banned' % site) if self.rssFlag: result = self.sitestatus.setSiteStatus(site, 'Banned', comment) else: result = WMSAdministratorClient().banSite(site, comment) if not result['OK']: return result if printOutput: gLogger.notice('Site %s status is set to Banned' % site) return result ############################################################################# def __checkSiteIsValid(self, site): """Internal function to check that a site name is valid. """ if isinstance(site, (list, set, dict)): site = set(site) - self._siteSet if not site: return S_OK() elif site in self._siteSet: return S_OK() return S_ERROR('Specified site %s is not in list of defined sites' % str(site)) ############################################################################# def getServicePorts(self, setup='', printOutput=False): """Checks the service ports for the specified setup. If not given this is taken from the current installation (/DIRAC/Setup) Example usage: >>> gLogger.notice(diracAdmin.getServicePorts()) {'OK': True, 'Value':''} :return: S_OK,S_ERROR """ if not setup: setup = gConfig.getValue('/DIRAC/Setup', '') setupList = gConfig.getSections('/DIRAC/Setups', []) if not setupList['OK']: return S_ERROR('Could not get /DIRAC/Setups sections') setupList = setupList['Value'] if setup not in setupList: return S_ERROR('Setup %s is not in allowed list: %s' % (setup, ', '.join(setupList))) serviceSetups = gConfig.getOptionsDict('/DIRAC/Setups/%s' % setup) if not serviceSetups['OK']: return S_ERROR('Could not get /DIRAC/Setups/%s options' % setup) serviceSetups = serviceSetups['Value'] # dict systemList = gConfig.getSections('/Systems') if not systemList['OK']: return S_ERROR('Could not get Systems sections') systemList = systemList['Value'] result = {} for system in systemList: if system in serviceSetups: path = '/Systems/%s/%s/Services' % (system, serviceSetups[system]) servicesList = gConfig.getSections(path) if not servicesList['OK']: self.log.warn('Could not get sections in %s' % path) else: servicesList = servicesList['Value'] if not servicesList: servicesList = [] self.log.verbose('System: %s ServicesList: %s' % (system, ', '.join(servicesList))) for service in servicesList: spath = '%s/%s/Port' % (path, service) servicePort = gConfig.getValue(spath, 0) if servicePort: self.log.verbose('Found port for %s/%s = %s' % (system, service, servicePort)) result['%s/%s' % (system, service)] = servicePort else: self.log.warn('No port found for %s' % spath) else: self.log.warn('%s is not defined in /DIRAC/Setups/%s' % (system, setup)) if printOutput: gLogger.notice(self.pPrint.pformat(result)) return S_OK(result) ############################################################################# def getProxy(self, userDN, userGroup, validity=43200, limited=False): """Retrieves a proxy with default 12hr validity and stores this in a file in the local directory by default. Example usage: >>> gLogger.notice(diracAdmin.getProxy()) {'OK': True, 'Value': } :return: S_OK,S_ERROR """ return gProxyManager.downloadProxy(userDN, userGroup, limited=limited, requiredTimeLeft=validity) ############################################################################# def getVOMSProxy(self, userDN, userGroup, vomsAttr=False, validity=43200, limited=False): """Retrieves a proxy with default 12hr validity and VOMS extensions and stores this in a file in the local directory by default. Example usage: >>> gLogger.notice(diracAdmin.getVOMSProxy()) {'OK': True, 'Value': } :return: S_OK,S_ERROR """ return gProxyManager.downloadVOMSProxy(userDN, userGroup, limited=limited, requiredVOMSAttribute=vomsAttr, requiredTimeLeft=validity) ############################################################################# def getPilotProxy(self, userDN, userGroup, validity=43200): """Retrieves a pilot proxy with default 12hr validity and stores this in a file in the local directory by default. Example usage: >>> gLogger.notice(diracAdmin.getVOMSProxy()) {'OK': True, 'Value': } :return: S_OK,S_ERROR """ return gProxyManager.getPilotProxyFromDIRACGroup( userDN, userGroup, requiredTimeLeft=validity) ############################################################################# def resetJob(self, jobID): """Reset a job or list of jobs in the WMS. This operation resets the reschedule counter for a job or list of jobs and allows them to run as new. Example:: >>> gLogger.notice(dirac.reset(12345)) {'OK': True, 'Value': [12345]} :param job: JobID :type job: integer or list of integers :return: S_OK,S_ERROR """ if isinstance(jobID, six.string_types): try: jobID = int(jobID) except Exception as x: return self._errorReport( str(x), 'Expected integer or convertible integer for existing jobID' ) elif isinstance(jobID, list): try: jobID = [int(job) for job in jobID] except Exception as x: return self._errorReport( str(x), 'Expected integer or convertible integer for existing jobIDs' ) result = JobManagerClient(useCertificates=False).resetJob(jobID) return result ############################################################################# def getJobPilotOutput(self, jobID, directory=''): """Retrieve the pilot output for an existing job in the WMS. The output will be retrieved in a local directory unless otherwise specified. >>> gLogger.notice(dirac.getJobPilotOutput(12345)) {'OK': True, StdOut:'',StdError:''} :param job: JobID :type job: integer or string :return: S_OK,S_ERROR """ if not directory: directory = self.currentDir if not os.path.exists(directory): return self._errorReport('Directory %s does not exist' % directory) result = WMSAdministratorClient().getJobPilotOutput(jobID) if not result['OK']: return result outputPath = '%s/pilot_%s' % (directory, jobID) if os.path.exists(outputPath): self.log.info('Remove %s and retry to continue' % outputPath) return S_ERROR('Remove %s and retry to continue' % outputPath) if not os.path.exists(outputPath): self.log.verbose('Creating directory %s' % outputPath) os.mkdir(outputPath) outputs = result['Value'] if 'StdOut' in outputs: stdout = '%s/std.out' % (outputPath) with open(stdout, 'w') as fopen: fopen.write(outputs['StdOut']) self.log.verbose('Standard output written to %s' % (stdout)) else: self.log.warn('No standard output returned') if 'StdError' in outputs: stderr = '%s/std.err' % (outputPath) with open(stderr, 'w') as fopen: fopen.write(outputs['StdError']) self.log.verbose('Standard error written to %s' % (stderr)) else: self.log.warn('No standard error returned') self.log.always('Outputs retrieved in %s' % outputPath) return result ############################################################################# def getPilotOutput(self, gridReference, directory=''): """Retrieve the pilot output (std.out and std.err) for an existing job in the WMS. >>> gLogger.notice(dirac.getJobPilotOutput(12345)) {'OK': True, 'Value': {}} :param job: JobID :type job: integer or string :return: S_OK,S_ERROR """ if not isinstance(gridReference, six.string_types): return self._errorReport('Expected string for pilot reference') if not directory: directory = self.currentDir if not os.path.exists(directory): return self._errorReport('Directory %s does not exist' % directory) result = PilotManagerClient().getPilotOutput(gridReference) if not result['OK']: return result gridReferenceSmall = gridReference.split('/')[-1] if not gridReferenceSmall: gridReferenceSmall = 'reference' outputPath = '%s/pilot_%s' % (directory, gridReferenceSmall) if os.path.exists(outputPath): self.log.info('Remove %s and retry to continue' % outputPath) return S_ERROR('Remove %s and retry to continue' % outputPath) if not os.path.exists(outputPath): self.log.verbose('Creating directory %s' % outputPath) os.mkdir(outputPath) outputs = result['Value'] if 'StdOut' in outputs: stdout = '%s/std.out' % (outputPath) with open(stdout, 'w') as fopen: fopen.write(outputs['StdOut']) self.log.info('Standard output written to %s' % (stdout)) else: self.log.warn('No standard output returned') if 'StdErr' in outputs: stderr = '%s/std.err' % (outputPath) with open(stderr, 'w') as fopen: fopen.write(outputs['StdErr']) self.log.info('Standard error written to %s' % (stderr)) else: self.log.warn('No standard error returned') self.log.always('Outputs retrieved in %s' % outputPath) return result ############################################################################# def getPilotInfo(self, gridReference): """Retrieve info relative to a pilot reference >>> gLogger.notice(dirac.getPilotInfo(12345)) {'OK': True, 'Value': {}} :param gridReference: Pilot Job Reference :type gridReference: string :return: S_OK,S_ERROR """ if not isinstance(gridReference, six.string_types): return self._errorReport('Expected string for pilot reference') result = PilotManagerClient().getPilotInfo(gridReference) return result ############################################################################# def killPilot(self, gridReference): """Kill the pilot specified >>> gLogger.notice(dirac.getPilotInfo(12345)) {'OK': True, 'Value': {}} :param gridReference: Pilot Job Reference :return: S_OK,S_ERROR """ if not isinstance(gridReference, six.string_types): return self._errorReport('Expected string for pilot reference') result = PilotManagerClient().killPilot(gridReference) return result ############################################################################# def getPilotLoggingInfo(self, gridReference): """Retrieve the pilot logging info for an existing job in the WMS. >>> gLogger.notice(dirac.getPilotLoggingInfo(12345)) {'OK': True, 'Value': {"The output of the command"}} :param gridReference: Gridp pilot job reference Id :type gridReference: string :return: S_OK,S_ERROR """ if not isinstance(gridReference, six.string_types): return self._errorReport('Expected string for pilot reference') return PilotManagerClient().getPilotLoggingInfo(gridReference) ############################################################################# def getJobPilots(self, jobID): """Extract the list of submitted pilots and their status for a given jobID from the WMS. Useful information is printed to the screen. >>> gLogger.notice(dirac.getJobPilots()) {'OK': True, 'Value': {PilotID:{StatusDict}}} :param job: JobID :type job: integer or string :return: S_OK,S_ERROR """ if isinstance(jobID, six.string_types): try: jobID = int(jobID) except Exception as x: return self._errorReport( str(x), 'Expected integer or string for existing jobID') result = PilotManagerClient().getPilots(jobID) if result['OK']: gLogger.notice(self.pPrint.pformat(result['Value'])) return result ############################################################################# def getPilotSummary(self, startDate='', endDate=''): """Retrieve the pilot output for an existing job in the WMS. Summary is printed at INFO level, full dictionary of results also returned. >>> gLogger.notice(dirac.getPilotSummary()) {'OK': True, 'Value': {CE:{Status:Count}}} :param job: JobID :type job: integer or string :return: S_OK,S_ERROR """ result = PilotManagerClient().getPilotSummary(startDate, endDate) if not result['OK']: return result ceDict = result['Value'] headers = 'CE'.ljust(28) i = 0 for ce, summary in ceDict.iteritems(): states = summary.keys() if len(states) > i: i = len(states) for i in xrange(i): headers += 'Status'.ljust(12) + 'Count'.ljust(12) gLogger.notice(headers) for ce, summary in ceDict.iteritems(): line = ce.ljust(28) states = sorted(summary) for state in states: count = str(summary[state]) line += state.ljust(12) + count.ljust(12) gLogger.notice(line) return result ############################################################################# def setSiteProtocols(self, site, protocolsList, printOutput=False): """ Allows to set the defined protocols for each SE for a given site. """ result = self.__checkSiteIsValid(site) if not result['OK']: return result siteSection = '/Resources/Sites/%s/%s/SE' % (site.split('.')[0], site) siteSEs = gConfig.getValue(siteSection, []) if not siteSEs: return S_ERROR('No SEs found for site %s in section %s' % (site, siteSection)) defaultProtocols = gConfig.getValue( '/Resources/StorageElements/DefaultProtocols', []) self.log.verbose('Default list of protocols are', ', '.join(defaultProtocols)) for protocol in protocolsList: if protocol not in defaultProtocols: return S_ERROR( 'Requested to set protocol %s in list but %s is not ' 'in default list of protocols:\n%s' % (protocol, protocol, ', '.join(defaultProtocols))) modifiedCS = False result = promptUser( 'Do you want to add the following default protocols:' ' %s for SE(s):\n%s' % (', '.join(protocolsList), ', '.join(siteSEs))) if not result['OK']: return result if result['Value'].lower() != 'y': self.log.always('No protocols will be added') return S_OK() for se in siteSEs: sections = gConfig.getSections('/Resources/StorageElements/%s/' % (se)) if not sections['OK']: return sections for section in sections['Value']: if gConfig.getValue( '/Resources/StorageElements/%s/%s/ProtocolName' % (se, section), '') == 'SRM2': path = '/Resources/StorageElements/%s/%s/ProtocolsList' % ( se, section) self.log.verbose('Setting %s to %s' % (path, ', '.join(protocolsList))) result = self.csSetOption(path, ', '.join(protocolsList)) if not result['OK']: return result modifiedCS = True if modifiedCS: result = self.csCommitChanges(False) if not result['OK']: return S_ERROR('CS Commit failed with message = %s' % (result['Message'])) else: if printOutput: gLogger.notice('Successfully committed changes to CS') else: if printOutput: gLogger.notice('No modifications to CS required') return S_OK() ############################################################################# def csSetOption(self, optionPath, optionValue): """ Function to modify an existing value in the CS. """ return self.csAPI.setOption(optionPath, optionValue) ############################################################################# def csSetOptionComment(self, optionPath, comment): """ Function to modify an existing value in the CS. """ return self.csAPI.setOptionComment(optionPath, comment) ############################################################################# def csModifyValue(self, optionPath, newValue): """ Function to modify an existing value in the CS. """ return self.csAPI.modifyValue(optionPath, newValue) ############################################################################# def csRegisterUser(self, username, properties): """ Registers a user in the CS. - username: Username of the user (easy;) - properties: Dict containing: - DN - groups : list/tuple of groups the user belongs to - <others> : More properties of the user, like mail """ return self.csAPI.addUser(username, properties) ############################################################################# def csDeleteUser(self, user): """ Deletes a user from the CS. Can take a list of users """ return self.csAPI.deleteUsers(user) ############################################################################# def csModifyUser(self, username, properties, createIfNonExistant=False): """ Modify a user in the CS. Takes the same params as in addUser and applies the changes """ return self.csAPI.modifyUser(username, properties, createIfNonExistant) ############################################################################# def csListUsers(self, group=False): """ Lists the users in the CS. If no group is specified return all users. """ return self.csAPI.listUsers(group) ############################################################################# def csDescribeUsers(self, mask=False): """ List users and their properties in the CS. If a mask is given, only users in the mask will be returned """ return self.csAPI.describeUsers(mask) ############################################################################# def csModifyGroup(self, groupname, properties, createIfNonExistant=False): """ Modify a user in the CS. Takes the same params as in addGroup and applies the changes """ return self.csAPI.modifyGroup(groupname, properties, createIfNonExistant) ############################################################################# def csListHosts(self): """ Lists the hosts in the CS """ return self.csAPI.listHosts() ############################################################################# def csDescribeHosts(self, mask=False): """ Gets extended info for the hosts in the CS """ return self.csAPI.describeHosts(mask) ############################################################################# def csModifyHost(self, hostname, properties, createIfNonExistant=False): """ Modify a host in the CS. Takes the same params as in addHost and applies the changes """ return self.csAPI.modifyHost(hostname, properties, createIfNonExistant) ############################################################################# def csListGroups(self): """ Lists groups in the CS """ return self.csAPI.listGroups() ############################################################################# def csDescribeGroups(self, mask=False): """ List groups and their properties in the CS. If a mask is given, only groups in the mask will be returned """ return self.csAPI.describeGroups(mask) ############################################################################# def csSyncUsersWithCFG(self, usersCFG): """ Synchronize users in cfg with its contents """ return self.csAPI.syncUsersWithCFG(usersCFG) ############################################################################# def csCommitChanges(self, sortUsers=True): """ Commit the changes in the CS """ return self.csAPI.commitChanges(sortUsers=False) ############################################################################# def sendMail(self, address, subject, body, fromAddress=None, localAttempt=True, html=False): """ Send mail to specified address with body. """ notification = NotificationClient() return notification.sendMail(address, subject, body, fromAddress, localAttempt, html) ############################################################################# def sendSMS(self, userName, body, fromAddress=None): """ Send mail to specified address with body. """ if len(body) > 160: return S_ERROR('Exceeded maximum SMS length of 160 characters') notification = NotificationClient() return notification.sendSMS(userName, body, fromAddress) ############################################################################# def getBDIISite(self, site, host=None): """ Get information about site from BDII at host """ return ldapSite(site, host=host) ############################################################################# def getBDIICluster(self, ce, host=None): """ Get information about ce from BDII at host """ return ldapCluster(ce, host=host) ############################################################################# def getBDIICE(self, ce, host=None): """ Get information about ce from BDII at host """ return ldapCE(ce, host=host) ############################################################################# def getBDIIService(self, ce, host=None): """ Get information about ce from BDII at host """ return ldapService(ce, host=host) ############################################################################# def getBDIICEState(self, ce, useVO=voName, host=None): """ Get information about ce state from BDII at host """ return ldapCEState(ce, useVO, host=host) ############################################################################# def getBDIICEVOView(self, ce, useVO=voName, host=None): """ Get information about ce voview from BDII at host """ return ldapCEVOView(ce, useVO, host=host) ############################################################################# def getBDIISE(self, site, useVO=voName, host=None): """ Get information about SA from BDII at host """ return ldapSE(site, useVO, host=host)
class Bdii2CSAgent(AgentModule): def __init__(self, *args, **kwargs): """ Defines default parameters """ super(Bdii2CSAgent, self).__init__(*args, **kwargs) self.addressTo = '' self.addressFrom = '' self.voName = [] self.subject = "Bdii2CSAgent" self.alternativeBDIIs = [] self.voBdiiCEDict = {} self.voBdiiSEDict = {} self.host = 'lcg-bdii.cern.ch:2170' self.glue2URLs = [] self.glue2Only = False self.csAPI = None # What to get self.processCEs = True self.processSEs = False self.selectedSites = [] # Update the CS or not? self.dryRun = False def initialize(self): """ Gets run paramaters from the configuration """ self.addressTo = self.am_getOption('MailTo', self.addressTo) self.addressFrom = self.am_getOption('MailFrom', self.addressFrom) # Create a list of alternative bdii urls self.alternativeBDIIs = self.am_getOption('AlternativeBDIIs', self.alternativeBDIIs) self.host = self.am_getOption('Host', self.host) self.glue2URLs = self.am_getOption('GLUE2URLs', self.glue2URLs) self.glue2Only = self.am_getOption('GLUE2Only', self.glue2Only) # Check if the bdii url is appended by a port number, if not append the default 2170 for index, url in enumerate(self.alternativeBDIIs): if not url.split(':')[-1].isdigit(): self.alternativeBDIIs[index] += ':2170' if self.addressTo and self.addressFrom: self.log.info("MailTo", self.addressTo) self.log.info("MailFrom", self.addressFrom) if self.alternativeBDIIs: self.log.info("AlternativeBDII URLs:", self.alternativeBDIIs) self.processCEs = self.am_getOption('ProcessCEs', self.processCEs) self.processSEs = self.am_getOption('ProcessSEs', self.processSEs) self.selectedSites = self.am_getOption('SelectedSites', []) self.dryRun = self.am_getOption('DryRun', self.dryRun) self.voName = self.am_getOption('VirtualOrganization', self.voName) if not self.voName: self.voName = self.am_getOption('VO', []) if not self.voName or (len(self.voName) == 1 and self.voName[0].lower() == 'all'): # Get all VOs defined in the configuration self.voName = [] result = getVOs() if result['OK']: vos = result['Value'] for vo in vos: vomsVO = getVOOption(vo, "VOMSName") if vomsVO: self.voName.append(vomsVO) if self.voName: self.log.info("Agent will manage VO(s) %s" % self.voName) else: self.log.fatal("VirtualOrganization option not defined for agent") return S_ERROR() self.csAPI = CSAPI() return self.csAPI.initialize() def execute(self): """ General agent execution method """ self.voBdiiCEDict = {} self.voBdiiSEDict = {} # Get a "fresh" copy of the CS data result = self.csAPI.downloadCSData() if not result['OK']: self.log.warn("Could not download a fresh copy of the CS data", result['Message']) # Refresh the configuration from the master server gConfig.forceRefresh(fromMaster=True) if self.processCEs: self.__lookForNewCEs() self.__updateCEs() if self.processSEs: self.__lookForNewSEs() self.__updateSEs() return S_OK() def __lookForNewCEs(self): """ Look up BDII for CEs not yet present in the DIRAC CS """ bannedCEs = self.am_getOption('BannedCEs', []) result = getCEsFromCS() if not result['OK']: return result knownCEs = set(result['Value']) knownCEs = knownCEs.union(set(bannedCEs)) for vo in self.voName: result = self.__getBdiiCEInfo(vo) if not result['OK']: continue bdiiInfo = result['Value'] result = getGridCEs(vo, bdiiInfo=bdiiInfo, ceBlackList=knownCEs) if not result['OK']: self.log.error('Failed to get unused CEs', result['Message']) siteDict = result['Value'] body = '' for site in siteDict: newCEs = set(siteDict[site].keys()) # pylint: disable=no-member if not newCEs: continue ceString = '' for ce in newCEs: queueString = '' ceInfo = bdiiInfo[site]['CEs'][ce] newCEString = "CE: %s, GOCDB Site Name: %s" % (ce, site) systemTuple = siteDict[site][ce]['System'] osString = "%s_%s_%s" % (systemTuple) newCEString = "\n%s\n%s\n" % (newCEString, osString) for queue in ceInfo['Queues']: queueStatus = ceInfo['Queues'][queue].get('GlueCEStateStatus', 'UnknownStatus') if 'production' in queueStatus.lower(): ceType = ceInfo['Queues'][queue].get('GlueCEImplementationName', '') queueString += " %s %s %s\n" % (queue, queueStatus, ceType) if queueString: ceString += newCEString ceString += "Queues:\n" ceString += queueString if ceString: body += ceString if body: body = "\nWe are glad to inform You about new CE(s) possibly suitable for %s:\n" % vo + body body += "\n\nTo suppress information about CE add its name to BannedCEs list.\n" body += "Add new Sites/CEs for vo %s with the command:\n" % vo body += "dirac-admin-add-resources --vo %s --ce\n" % vo self.log.info(body) if self.addressTo and self.addressFrom: notification = NotificationClient() result = notification.sendMail(self.addressTo, self.subject, body, self.addressFrom, localAttempt=False, avoidSpam=True) if not result['OK']: self.log.error('Can not send new site notification mail', result['Message']) return S_OK() def __getBdiiCEInfo(self, vo): if vo in self.voBdiiCEDict: return S_OK(self.voBdiiCEDict[vo]) self.log.info("Check for available CEs for VO", vo) totalResult = S_OK({}) message = '' mainResult = getBdiiCEInfo(vo, host=self.host, glue2=self.glue2Only) if not mainResult['OK']: self.log.error("Failed getting information from default bdii", mainResult['Message']) message = mainResult['Message'] for bdii in reversed(self.alternativeBDIIs): resultAlt = getBdiiCEInfo(vo, host=bdii, glue2=self.glue2Only) if resultAlt['OK']: totalResult['Value'].update(resultAlt['Value']) else: self.log.error("Failed getting information from %s " % bdii, resultAlt['Message']) message = (message + "\n" + resultAlt['Message']).strip() for glue2URL in self.glue2URLs: if self.glue2Only: break resultGlue2 = getBdiiCEInfo(vo, host=glue2URL, glue2=True) if resultGlue2['OK']: totalResult['Value'].update(resultGlue2['Value']) else: self.log.error("Failed getting GLUE2 information for", "%s, %s: %s" % (glue2URL, vo, resultGlue2['Message'])) message = (message + "\n" + resultGlue2['Message']).strip() if mainResult['OK']: totalResult['Value'].update(mainResult['Value']) if not totalResult['Value'] and message: # Dict is empty and we have an error message self.log.error("Error during BDII request", message) totalResult = S_ERROR(message) else: self.voBdiiCEDict[vo] = totalResult['Value'] return totalResult def __getBdiiSEInfo(self, vo): if vo in self.voBdiiSEDict: return S_OK(self.voBdiiSEDict[vo]) self.log.info("Check for available SEs for VO", vo) result = getBdiiSEInfo(vo) message = '' if not result['OK']: message = result['Message'] for bdii in self.alternativeBDIIs: result = getBdiiSEInfo(vo, host=bdii) if result['OK']: break if not result['OK']: if message: self.log.error("Error during BDII request", message) else: self.log.error("Error during BDII request", result['Message']) else: self.voBdiiSEDict[vo] = result['Value'] return result def __updateCEs(self): """ Update the Site/CE/queue settings in the CS if they were changed in the BDII """ bdiiChangeSet = set() for vo in self.voName: result = self.__getBdiiCEInfo(vo) if not result['OK']: continue ceBdiiDict = result['Value'] self.__purgeSites(ceBdiiDict) result = getSiteUpdates(vo, bdiiInfo=ceBdiiDict, log=self.log) if not result['OK']: continue bdiiChangeSet = bdiiChangeSet.union(result['Value']) # We have collected all the changes, consolidate VO settings result = self.__updateCS(bdiiChangeSet) return result def __purgeSites(self, ceBdiiDict): """Remove all sites that are not in self.selectedSites. Modifies the ceBdiiDict! """ if not self.selectedSites: return for site in list(ceBdiiDict): ces = list(ceBdiiDict[site]['CEs']) if not ces: self.log.error("No CE information for site:", site) continue diracSiteName = getSiteForCE(ces[0]) if not diracSiteName['OK']: self.log.error("Failed to get DIRAC site name for ce", "%s: %s" % (ces[0], diracSiteName['Message'])) continue self.log.debug("Checking site %s (%s), aka %s" % (site, ces, diracSiteName['Value'])) if diracSiteName['Value'] in self.selectedSites: continue self.log.info("Dropping site %s, aka %s" % (site, diracSiteName)) ceBdiiDict.pop(site) return def __updateCS(self, bdiiChangeSet): queueVODict = {} changeSet = set() for entry in bdiiChangeSet: section, option, _value, new_value = entry if option == "VO": queueVODict.setdefault(section, set()) queueVODict[section] = queueVODict[section].union(set(new_value.split(','))) else: changeSet.add(entry) for section, VOs in queueVODict.items(): changeSet.add((section, 'VO', '', ','.join(VOs))) if changeSet: changeList = sorted(changeSet) body = '\n'.join(["%s/%s %s -> %s" % entry for entry in changeList]) if body and self.addressTo and self.addressFrom: notification = NotificationClient() result = notification.sendMail(self.addressTo, self.subject, body, self.addressFrom, localAttempt=False) if body: self.log.info('The following configuration changes were detected:') self.log.info(body) for section, option, value, new_value in changeSet: if value == 'Unknown' or not value: self.csAPI.setOption(cfgPath(section, option), new_value) else: self.csAPI.modifyValue(cfgPath(section, option), new_value) if self.dryRun: self.log.info("Dry Run: CS won't be updated") self.csAPI.showDiff() else: result = self.csAPI.commit() if not result['OK']: self.log.error("Error while committing to CS", result['Message']) else: self.log.info("Successfully committed %d changes to CS" % len(changeList)) return result else: self.log.info("No changes found") return S_OK() def __lookForNewSEs(self): """ Look up BDII for SEs not yet present in the DIRAC CS """ bannedSEs = self.am_getOption('BannedSEs', []) result = getSEsFromCS() if not result['OK']: return result knownSEs = set(result['Value']) knownSEs = knownSEs.union(set(bannedSEs)) for vo in self.voName: result = self.__getBdiiSEInfo(vo) if not result['OK']: continue bdiiInfo = result['Value'] result = getGridSRMs(vo, bdiiInfo=bdiiInfo, srmBlackList=knownSEs) if not result['OK']: continue siteDict = result['Value'] body = '' for site in siteDict: newSEs = set(siteDict[site].keys()) # pylint: disable=no-member if not newSEs: continue for se in newSEs: body += '\n New SE %s available at site %s:\n' % (se, site) backend = siteDict[site][se]['SE'].get('GlueSEImplementationName', 'Unknown') size = siteDict[site][se]['SE'].get('GlueSESizeTotal', 'Unknown') body += ' Backend %s, Size %s' % (backend, size) if body: body = "\nWe are glad to inform You about new SE(s) possibly suitable for %s:\n" % vo + body body += "\n\nTo suppress information about an SE add its name to BannedSEs list.\n" body += "Add new SEs for vo %s with the command:\n" % vo body += "dirac-admin-add-resources --vo %s --se\n" % vo self.log.info(body) if self.addressTo and self.addressFrom: notification = NotificationClient() result = notification.sendMail(self.addressTo, self.subject, body, self.addressFrom, localAttempt=False) if not result['OK']: self.log.error('Can not send new site notification mail', result['Message']) return S_OK() def __updateSEs(self): """ Update the Storage Element settings in the CS if they were changed in the BDII """ bdiiChangeSet = set() for vo in self.voName: result = self.__getBdiiSEInfo(vo) if not result['OK']: continue seBdiiDict = result['Value'] result = getSRMUpdates(vo, bdiiInfo=seBdiiDict) if not result['OK']: continue bdiiChangeSet = bdiiChangeSet.union(result['Value']) # We have collected all the changes, consolidate VO settings result = self.__updateCS(bdiiChangeSet) return result
"Systems/DataManagement", "Systems/DataManagement/Production", "Systems/DataManagement/Production/Databases", "Systems/DataManagement/Production/Databases/FileCatalogDB", "Systems/DataManagement/Production/Databases/MultiVOFileCatalogDB", ]: res = csAPI.createSection(sct) if not res["OK"]: print(res["Message"]) exit(1) dbHost = os.environ["DB_HOST"] dbPort = os.environ["DB_PORT"] csAPI.setOption( "Systems/DataManagement/Production/Databases/FileCatalogDB/DBName", "FileCatalogDB") csAPI.setOption( "Systems/DataManagement/Production/Databases/FileCatalogDB/Host", dbHost) csAPI.setOption( "Systems/DataManagement/Production/Databases/FileCatalogDB/Port", dbPort) csAPI.setOption( "Systems/DataManagement/Production/Databases/MultiVOFileCatalogDB/DBName", "MultiVOFileCatalogDB") csAPI.setOption( "Systems/DataManagement/Production/Databases/MultiVOFileCatalogDB/Host", dbHost) csAPI.setOption( "Systems/DataManagement/Production/Databases/MultiVOFileCatalogDB/Port", dbPort)
def checkUnusedSEs(): global vo, dry result = getGridSRMs( vo, unUsed = True ) if not result['OK']: gLogger.error( 'Failed to look up SRMs in BDII', result['Message'] ) siteSRMDict = result['Value'] # Evaluate VOs result = getVOs() if result['OK']: csVOs = set( result['Value'] ) else: csVOs = set( [vo] ) changeSetFull = set() for site in siteSRMDict: for gridSE in siteSRMDict[site]: changeSet = set() seDict = siteSRMDict[site][gridSE]['SE'] srmDict = siteSRMDict[site][gridSE]['SRM'] # Check the SRM version version = srmDict.get( 'GlueServiceVersion', '' ) if not ( version and version.startswith( '2' ) ): gLogger.debug( 'Skipping SRM service with version %s' % version ) continue result = getDIRACSiteName( site ) if not result['OK']: gLogger.notice( 'Unused se %s is detected at unused site %s' % ( gridSE, site ) ) gLogger.notice( 'Consider adding site %s to the DIRAC CS' % site ) continue diracSites = result['Value'] yn = raw_input( '\nDo you want to add new SRM SE %s at site(s) %s ? default yes [yes|no]: ' % ( gridSE, str( diracSites ) ) ) if not yn or yn.lower().startswith( 'y' ): if len( diracSites ) > 1: prompt = 'Which DIRAC site the new SE should be attached to ?' for i, s in enumerate( diracSites ): prompt += '\n[%d] %s' % ( i, s ) prompt += '\nEnter your choice number: ' inp = raw_input( prompt ) try: ind = int( inp ) except: gLogger.notice( 'Can not interpret your choice: %s, try again later' % inp ) continue diracSite = diracSites[ind] else: diracSite = diracSites[0] domain, siteName, country = diracSite.split( '.' ) recName = '%s-disk' % siteName inp = raw_input( 'Give a DIRAC name to the grid SE %s, default %s : ' % ( gridSE, recName ) ) diracSEName = inp if not inp: diracSEName = recName gLogger.notice( 'Adding new SE %s at site %s' % ( diracSEName, diracSite ) ) seSection = cfgPath( '/Resources/StorageElements', diracSEName ) changeSet.add( ( seSection, 'BackendType', seDict.get( 'GlueSEImplementationName', 'Unknown' ) ) ) changeSet.add( ( seSection, 'Description', seDict.get( 'GlueSEName', 'Unknown' ) ) ) bdiiVOs = set( [ re.sub( '^VO:', '', rule ) for rule in srmDict.get( 'GlueServiceAccessControlBaseRule', [] ) ] ) seVOs = csVOs.intersection( bdiiVOs ) changeSet.add( ( seSection, 'VO', ','.join( seVOs ) ) ) accessSection = cfgPath( seSection, 'AccessProtocol.1' ) changeSet.add( ( accessSection, 'Protocol', 'srm' ) ) changeSet.add( ( accessSection, 'ProtocolName', 'SRM2' ) ) endPoint = srmDict.get( 'GlueServiceEndpoint', '' ) result = pfnparse( endPoint ) if not result['OK']: gLogger.error( 'Can not get the SRM service end point. Skipping ...' ) continue host = result['Value']['Host'] port = result['Value']['Port'] changeSet.add( ( accessSection, 'Host', host ) ) changeSet.add( ( accessSection, 'Port', port ) ) changeSet.add( ( accessSection, 'Access', 'remote' ) ) voPathSection = cfgPath( accessSection, 'VOPath' ) if 'VOPath' in seDict: path = seDict['VOPath'] voFromPath = os.path.basename( path ) if voFromPath != diracVO: gLogger.notice( '\n!!! Warning: non-conventional VO path: %s\n' % path ) changeSet.add( ( voPathSection, diracVO, path ) ) path = os.path.dirname( path ) else: # Try to guess the Path domain = '.'.join( host.split( '.' )[-2:] ) path = '/dpm/%s/home' % domain changeSet.add( ( accessSection, 'Path', path ) ) changeSet.add( ( accessSection, 'SpaceToken', '' ) ) changeSet.add( ( accessSection, 'WSUrl', '/srm/managerv2?SFN=' ) ) gLogger.notice( 'SE %s will be added with the following parameters' % diracSEName ) changeList = list( changeSet ) changeList.sort() for entry in changeList: gLogger.notice( entry ) yn = raw_input( 'Do you want to add new SE %s ? default yes [yes|no]: ' % diracSEName ) if not yn or yn.lower().startswith( 'y' ): changeSetFull = changeSetFull.union( changeSet ) if dry: if changeSetFull: gLogger.notice( 'Skipping commit of the new SE data in a dry run' ) else: gLogger.notice( "No new SE to be added" ) return S_OK() if changeSetFull: csAPI = CSAPI() csAPI.initialize() result = csAPI.downloadCSData() if not result['OK']: gLogger.error( 'Failed to initialize CSAPI object', result['Message'] ) DIRACExit( -1 ) changeList = list( changeSetFull ) changeList.sort() for section, option, value in changeList: csAPI.setOption( cfgPath( section, option ), value ) yn = raw_input( 'New SE data is accumulated\n Do you want to commit changes to CS ? default yes [yes|no]: ' ) if not yn or yn.lower().startswith( 'y' ): result = csAPI.commit() if not result['OK']: gLogger.error( "Error while commit to CS", result['Message'] ) else: gLogger.notice( "Successfully committed %d changes to CS" % len( changeSetFull ) ) else: gLogger.notice( "No new SE to be added" ) return S_OK()
class DiracAdmin( API ): """ Administrative functionalities """ ############################################################################# def __init__( self ): """Internal initialization of the DIRAC Admin API. """ super( DiracAdmin, self ).__init__() self.csAPI = CSAPI() self.dbg = False if gConfig.getValue( self.section + '/LogLevel', 'DEBUG' ) == 'DEBUG': self.dbg = True self.scratchDir = gConfig.getValue( self.section + '/ScratchDir', '/tmp' ) self.currentDir = os.getcwd() ############################################################################# def uploadProxy( self, group ): """Upload a proxy to the DIRAC WMS. This method Example usage: >>> print diracAdmin.uploadProxy('lhcb_pilot') {'OK': True, 'Value': 0L} :param group: DIRAC Group :type job: string :return: S_OK,S_ERROR :param permanent: Indefinitely update proxy :type permanent: boolean """ return gProxyManager.uploadProxy( diracGroup = group ) ############################################################################# def setProxyPersistency( self, userDN, userGroup, persistent = True ): """Set the persistence of a proxy in the Proxy Manager Example usage: >>> print diracAdmin.setProxyPersistency( 'some DN', 'dirac group', True ) {'OK': True } :param userDN: User DN :type userDN: string :param userGroup: DIRAC Group :type userGroup: string :param persistent: Persistent flag :type persistent: boolean :return: S_OK,S_ERROR """ return gProxyManager.setPersistency( userDN, userGroup, persistent ) ############################################################################# def checkProxyUploaded( self, userDN, userGroup, requiredTime ): """Set the persistence of a proxy in the Proxy Manager Example usage: >>> print diracAdmin.setProxyPersistency( 'some DN', 'dirac group', True ) {'OK': True, 'Value' : True/False } :param userDN: User DN :type userDN: string :param userGroup: DIRAC Group :type userGroup: string :param requiredTime: Required life time of the uploaded proxy :type requiredTime: boolean :return: S_OK,S_ERROR """ return gProxyManager.userHasProxy( userDN, userGroup, requiredTime ) ############################################################################# def getSiteMask( self, printOutput = False ): """Retrieve current site mask from WMS Administrator service. Example usage: >>> print diracAdmin.getSiteMask() {'OK': True, 'Value': 0L} :return: S_OK,S_ERROR """ wmsAdmin = RPCClient( 'WorkloadManagement/WMSAdministrator' ) result = wmsAdmin.getSiteMask() if result['OK']: sites = result['Value'] if printOutput: sites.sort() for site in sites: print site return result ############################################################################# def getBannedSites( self, gridType = [], printOutput = False ): """Retrieve current list of banned sites. Example usage: >>> print diracAdmin.getBannedSites() {'OK': True, 'Value': []} :return: S_OK,S_ERROR """ wmsAdmin = RPCClient( 'WorkloadManagement/WMSAdministrator' ) bannedSites = [] totalList = [] result = wmsAdmin.getSiteMask() if not result['OK']: self.log.warn( result['Message'] ) return result sites = result['Value'] if not gridType: result = gConfig.getSections( '/Resources/Sites' ) if not result['OK']: return result gridType = result['Value'] for grid in gridType: result = gConfig.getSections( '/Resources/Sites/%s' % grid ) if not result['OK']: return result totalList += result['Value'] for site in totalList: if not site in sites: bannedSites.append( site ) bannedSites.sort() if printOutput: print '\n'.join( bannedSites ) return S_OK( bannedSites ) ############################################################################# def getSiteSection( self, site, printOutput = False ): """Simple utility to get the list of CEs for DIRAC site name. Example usage: >>> print diracAdmin.getSiteSection('LCG.CERN.ch') {'OK': True, 'Value':} :return: S_OK,S_ERROR """ gridType = site.split( '.' )[0] if not gConfig.getSections( '/Resources/Sites/%s' % ( gridType ) )['OK']: return S_ERROR( '/Resources/Sites/%s is not a valid site section' % ( gridType ) ) result = gConfig.getOptionsDict( '/Resources/Sites/%s/%s' % ( gridType, site ) ) if printOutput and result['OK']: print self.pPrint.pformat( result['Value'] ) return result ############################################################################# def addSiteInMask( self, site, comment, printOutput = False ): """Adds the site to the site mask. Example usage: >>> print diracAdmin.addSiteInMask() {'OK': True, 'Value': } :return: S_OK,S_ERROR """ result = self.__checkSiteIsValid( site ) if not result['OK']: return result mask = self.getSiteMask() if not mask['OK']: return mask siteMask = mask['Value'] if site in siteMask: return S_ERROR( 'Site %s already in mask of allowed sites' % site ) wmsAdmin = RPCClient( 'WorkloadManagement/WMSAdministrator' ) result = wmsAdmin.allowSite( site, comment ) if not result['OK']: return result if printOutput: print 'Allowing %s in site mask' % site return result ############################################################################# def getSiteMaskLogging( self, site = None, printOutput = False ): """Retrieves site mask logging information. Example usage: >>> print diracAdmin.getSiteMaskLogging('LCG.AUVER.fr') {'OK': True, 'Value': } :return: S_OK,S_ERROR """ result = self.__checkSiteIsValid( site ) if not result['OK']: return result wmsAdmin = RPCClient( 'WorkloadManagement/WMSAdministrator' ) result = wmsAdmin.getSiteMaskLogging( site ) if not result['OK']: return result if site: if not result['Value'].has_key( site ): return S_ERROR( 'Site mask information not available for %s' % ( site ) ) if printOutput: if site: print '\nSite Mask Logging Info for %s\n' % site else: print '\nAll Site Mask Logging Info\n' siteDict = result['Value'] for site, tupleList in siteDict.iteritems(): if not site: print '\n===> %s\n' % site for tup in tupleList: print str( tup[0] ).ljust( 8 ) + str( tup[1] ).ljust( 20 ) + \ '( ' + str( tup[2] ).ljust( len( str( tup[2] ) ) ) + ' ) "' + str( tup[3] ) + '"' print ' ' return result ############################################################################# def banSiteFromMask( self, site, comment, printOutput = False ): """Removes the site from the site mask. Example usage: >>> print diracAdmin.banSiteFromMask() {'OK': True, 'Value': } :return: S_OK,S_ERROR """ result = self.__checkSiteIsValid( site ) if not result['OK']: return result mask = self.getSiteMask() if not mask['OK']: return mask siteMask = mask['Value'] if not site in siteMask: return S_ERROR( 'Site %s is already banned' % site ) wmsAdmin = RPCClient( 'WorkloadManagement/WMSAdministrator' ) result = wmsAdmin.banSite( site, comment ) if not result['OK']: return result if printOutput: print 'Removing %s from site mask' % site return result ############################################################################# @classmethod def __checkSiteIsValid( self, site ): """Internal function to check that a site name is valid. """ sites = getSiteCEMapping() if not sites['OK']: return S_ERROR( 'Could not get site CE mapping' ) siteList = sites['Value'].keys() if not site in siteList: return S_ERROR( 'Specified site %s is not in list of defined sites' % site ) return S_OK( '%s is valid' % site ) ############################################################################# def clearMask( self ): """Removes all sites from the site mask. Should be used with care. Example usage: >>> print diracAdmin.clearMask() {'OK': True, 'Value':''} :return: S_OK,S_ERROR """ wmsAdmin = RPCClient( 'WorkloadManagement/WMSAdministrator' ) result = wmsAdmin.clearMask() return result ############################################################################# def getServicePorts( self, setup = '', printOutput = False ): """Checks the service ports for the specified setup. If not given this is taken from the current installation (/DIRAC/Setup) Example usage: >>> print diracAdmin.getServicePorts() {'OK': True, 'Value':''} :return: S_OK,S_ERROR """ if not setup: setup = gConfig.getValue( '/DIRAC/Setup', '' ) setupList = gConfig.getSections( '/DIRAC/Setups', [] ) if not setupList['OK']: return S_ERROR( 'Could not get /DIRAC/Setups sections' ) setupList = setupList['Value'] if not setup in setupList: return S_ERROR( 'Setup %s is not in allowed list: %s' % ( setup, ', '.join( setupList ) ) ) serviceSetups = gConfig.getOptionsDict( '/DIRAC/Setups/%s' % setup ) if not serviceSetups['OK']: return S_ERROR( 'Could not get /DIRAC/Setups/%s options' % setup ) serviceSetups = serviceSetups['Value'] # dict systemList = gConfig.getSections( '/Systems' ) if not systemList['OK']: return S_ERROR( 'Could not get Systems sections' ) systemList = systemList['Value'] result = {} for system in systemList: if serviceSetups.has_key( system ): path = '/Systems/%s/%s/Services' % ( system, serviceSetups[system] ) servicesList = gConfig.getSections( path ) if not servicesList['OK']: self.log.warn( 'Could not get sections in %s' % path ) else: servicesList = servicesList['Value'] if not servicesList: servicesList = [] self.log.verbose( 'System: %s ServicesList: %s' % ( system, ', '.join( servicesList ) ) ) for service in servicesList: spath = '%s/%s/Port' % ( path, service ) servicePort = gConfig.getValue( spath, 0 ) if servicePort: self.log.verbose( 'Found port for %s/%s = %s' % ( system, service, servicePort ) ) result['%s/%s' % ( system, service )] = servicePort else: self.log.warn( 'No port found for %s' % spath ) else: self.log.warn( '%s is not defined in /DIRAC/Setups/%s' % ( system, setup ) ) if printOutput: print self.pPrint.pformat( result ) return S_OK( result ) ############################################################################# def getProxy( self, userDN, userGroup, validity = 43200, limited = False ): """Retrieves a proxy with default 12hr validity and stores this in a file in the local directory by default. Example usage: >>> print diracAdmin.getProxy() {'OK': True, 'Value': } :return: S_OK,S_ERROR """ return gProxyManager.downloadProxy( userDN, userGroup, limited = limited, requiredTimeLeft = validity ) ############################################################################# def getVOMSProxy( self, userDN, userGroup, vomsAttr = False, validity = 43200, limited = False ): """Retrieves a proxy with default 12hr validity and VOMS extensions and stores this in a file in the local directory by default. Example usage: >>> print diracAdmin.getVOMSProxy() {'OK': True, 'Value': } :return: S_OK,S_ERROR """ return gProxyManager.downloadVOMSProxy( userDN, userGroup, limited = limited, requiredVOMSAttribute = vomsAttr, requiredTimeLeft = validity ) ############################################################################# def getPilotProxy( self, userDN, userGroup, validity = 43200 ): """Retrieves a pilot proxy with default 12hr validity and stores this in a file in the local directory by default. Example usage: >>> print diracAdmin.getVOMSProxy() {'OK': True, 'Value': } :return: S_OK,S_ERROR """ return gProxyManager.getPilotProxyFromDIRACGroup( userDN, userGroup, requiredTimeLeft = validity ) ############################################################################# def resetJob( self, jobID ): """Reset a job or list of jobs in the WMS. This operation resets the reschedule counter for a job or list of jobs and allows them to run as new. Example:: >>> print dirac.reset(12345) {'OK': True, 'Value': [12345]} :param job: JobID :type job: integer or list of integers :return: S_OK,S_ERROR """ if isinstance( jobID, basestring ): try: jobID = int( jobID ) except Exception as x: return self._errorReport( str( x ), 'Expected integer or convertible integer for existing jobID' ) elif isinstance( jobID, list ): try: jobID = [int( job ) for job in jobID] except Exception as x: return self._errorReport( str( x ), 'Expected integer or convertible integer for existing jobIDs' ) jobManager = RPCClient( 'WorkloadManagement/JobManager', useCertificates = False ) result = jobManager.resetJob( jobID ) return result ############################################################################# def getJobPilotOutput( self, jobID, directory = '' ): """Retrieve the pilot output for an existing job in the WMS. The output will be retrieved in a local directory unless otherwise specified. >>> print dirac.getJobPilotOutput(12345) {'OK': True, StdOut:'',StdError:''} :param job: JobID :type job: integer or string :return: S_OK,S_ERROR """ if not directory: directory = self.currentDir if not os.path.exists( directory ): return self._errorReport( 'Directory %s does not exist' % directory ) wmsAdmin = RPCClient( 'WorkloadManagement/WMSAdministrator' ) result = wmsAdmin.getJobPilotOutput( jobID ) if not result['OK']: return result outputPath = '%s/pilot_%s' % ( directory, jobID ) if os.path.exists( outputPath ): self.log.info( 'Remove %s and retry to continue' % outputPath ) return S_ERROR( 'Remove %s and retry to continue' % outputPath ) if not os.path.exists( outputPath ): self.log.verbose( 'Creating directory %s' % outputPath ) os.mkdir( outputPath ) outputs = result['Value'] if outputs.has_key( 'StdOut' ): stdout = '%s/std.out' % ( outputPath ) with open( stdout, 'w' ) as fopen: fopen.write( outputs['StdOut'] ) self.log.verbose( 'Standard output written to %s' % ( stdout ) ) else: self.log.warn( 'No standard output returned' ) if outputs.has_key( 'StdError' ): stderr = '%s/std.err' % ( outputPath ) with open( stderr, 'w' ) as fopen: fopen.write( outputs['StdError'] ) self.log.verbose( 'Standard error written to %s' % ( stderr ) ) else: self.log.warn( 'No standard error returned' ) self.log.always( 'Outputs retrieved in %s' % outputPath ) return result ############################################################################# def getPilotOutput( self, gridReference, directory = '' ): """Retrieve the pilot output (std.out and std.err) for an existing job in the WMS. >>> print dirac.getJobPilotOutput(12345) {'OK': True, 'Value': {}} :param job: JobID :type job: integer or string :return: S_OK,S_ERROR """ if not isinstance( gridReference, basestring ): return self._errorReport( 'Expected string for pilot reference' ) if not directory: directory = self.currentDir if not os.path.exists( directory ): return self._errorReport( 'Directory %s does not exist' % directory ) wmsAdmin = RPCClient( 'WorkloadManagement/WMSAdministrator' ) result = wmsAdmin.getPilotOutput( gridReference ) if not result['OK']: return result gridReferenceSmall = gridReference.split( '/' )[-1] if not gridReferenceSmall: gridReferenceSmall = 'reference' outputPath = '%s/pilot_%s' % ( directory, gridReferenceSmall ) if os.path.exists( outputPath ): self.log.info( 'Remove %s and retry to continue' % outputPath ) return S_ERROR( 'Remove %s and retry to continue' % outputPath ) if not os.path.exists( outputPath ): self.log.verbose( 'Creating directory %s' % outputPath ) os.mkdir( outputPath ) outputs = result['Value'] if outputs.has_key( 'StdOut' ): stdout = '%s/std.out' % ( outputPath ) with open( stdout, 'w' ) as fopen: fopen.write( outputs['StdOut'] ) self.log.info( 'Standard output written to %s' % ( stdout ) ) else: self.log.warn( 'No standard output returned' ) if outputs.has_key( 'StdErr' ): stderr = '%s/std.err' % ( outputPath ) with open( stderr, 'w' ) as fopen: fopen.write( outputs['StdErr'] ) self.log.info( 'Standard error written to %s' % ( stderr ) ) else: self.log.warn( 'No standard error returned' ) self.log.always( 'Outputs retrieved in %s' % outputPath ) return result ############################################################################# def getPilotInfo( self, gridReference ): """Retrieve info relative to a pilot reference >>> print dirac.getPilotInfo(12345) {'OK': True, 'Value': {}} :param gridReference: Pilot Job Reference :type gridReference: string :return: S_OK,S_ERROR """ if not isinstance( gridReference, basestring ): return self._errorReport( 'Expected string for pilot reference' ) wmsAdmin = RPCClient( 'WorkloadManagement/WMSAdministrator' ) result = wmsAdmin.getPilotInfo( gridReference ) return result ############################################################################# def killPilot( self, gridReference ): """Kill the pilot specified >>> print dirac.getPilotInfo(12345) {'OK': True, 'Value': {}} :param gridReference: Pilot Job Reference :return: S_OK,S_ERROR """ if not isinstance( gridReference, basestring ): return self._errorReport( 'Expected string for pilot reference' ) wmsAdmin = RPCClient( 'WorkloadManagement/WMSAdministrator' ) result = wmsAdmin.killPilot( gridReference ) return result ############################################################################# def getPilotLoggingInfo( self, gridReference ): """Retrieve the pilot logging info for an existing job in the WMS. >>> print dirac.getPilotLoggingInfo(12345) {'OK': True, 'Value': {"The output of the command"}} :param gridReference: Gridp pilot job reference Id :type gridReference: string :return: S_OK,S_ERROR """ if type( gridReference ) not in types.StringTypes: return self._errorReport( 'Expected string for pilot reference' ) wmsAdmin = RPCClient( 'WorkloadManagement/WMSAdministrator' ) return wmsAdmin.getPilotLoggingInfo( gridReference ) ############################################################################# def getJobPilots( self, jobID ): """Extract the list of submitted pilots and their status for a given jobID from the WMS. Useful information is printed to the screen. >>> print dirac.getJobPilots() {'OK': True, 'Value': {PilotID:{StatusDict}}} :param job: JobID :type job: integer or string :return: S_OK,S_ERROR """ if isinstance( jobID, basestring ): try: jobID = int( jobID ) except Exception as x: return self._errorReport( str( x ), 'Expected integer or string for existing jobID' ) wmsAdmin = RPCClient( 'WorkloadManagement/WMSAdministrator' ) result = wmsAdmin.getPilots( jobID ) if result['OK']: print self.pPrint.pformat( result['Value'] ) return result ############################################################################# def getPilotSummary( self, startDate = '', endDate = '' ): """Retrieve the pilot output for an existing job in the WMS. Summary is printed at INFO level, full dictionary of results also returned. >>> print dirac.getPilotSummary() {'OK': True, 'Value': {CE:{Status:Count}}} :param job: JobID :type job: integer or string :return: S_OK,S_ERROR """ wmsAdmin = RPCClient( 'WorkloadManagement/WMSAdministrator' ) result = wmsAdmin.getPilotSummary( startDate, endDate ) if not result['OK']: return result ceDict = result['Value'] headers = 'CE'.ljust( 28 ) i = 0 for ce, summary in ceDict.iteritems(): states = summary.keys() if len( states ) > i: i = len( states ) for i in xrange( i ): headers += 'Status'.ljust( 12 ) + 'Count'.ljust( 12 ) print headers for ce, summary in ceDict.iteritems(): line = ce.ljust( 28 ) states = summary.keys() states.sort() for state in states: count = str( summary[state] ) line += state.ljust( 12 ) + count.ljust( 12 ) print line return result ############################################################################# def selectRequests( self, jobID = None, requestID = None, requestName = None, requestType = None, status = None, operation = None, ownerDN = None, ownerGroup = None, requestStart = 0, limit = 100, printOutput = False ): """Select requests from the request management system. A few notes on the selection criteria: - jobID is the WMS JobID for the request (if applicable) - requestID is assigned during submission of the request - requestName is the corresponding XML file name - requestType e.g. 'transfer' - status e.g. Done - operation e.g. replicateAndRegister - requestStart e.g. the first request to consider (start from 0 by default) - limit e.g. selection limit (default 100) >>> dirac.selectRequests(jobID='4894') {'OK': True, 'Value': [[<Requests>]]} """ options = {'RequestID':requestID, 'RequestName':requestName, 'JobID':jobID, 'OwnerDN':ownerDN, 'OwnerGroup':ownerGroup, 'RequestType':requestType, 'Status':status, 'Operation':operation} conditions = {} for key, value in options.iteritems(): if value: try: conditions[key] = str( value ) except Exception as x: return self._errorReport( str( x ), 'Expected string for %s field' % key ) try: requestStart = int( requestStart ) limit = int( limit ) except Exception as x: return self._errorReport( str( x ), 'Expected integer for %s field' % limit ) self.log.verbose( 'Will select requests with the following conditions' ) self.log.verbose( self.pPrint.pformat( conditions ) ) requestClient = RPCClient( "RequestManagement/centralURL" ) result = requestClient.getRequestSummaryWeb( conditions, [], requestStart, limit ) if not result['OK']: self.log.warn( result['Message'] ) return result requestIDs = result['Value'] conds = [] for key, value in conditions.iteritems(): if value: conds.append( '%s = %s' % ( key, value ) ) self.log.verbose( '%s request(s) selected with conditions %s and limit %s' % ( len( requestIDs['Records'] ), ', '.join( conds ), limit ) ) if printOutput: requests = [] if len( requestIDs['Records'] ) > limit: requestList = requestIDs['Records'] requests = requestList[:limit] else: requests = requestIDs['Records'] print '%s request(s) selected with conditions %s and limit %s' % ( len( requestIDs['Records'] ), ', '.join( conds ), limit ) print requestIDs['ParameterNames'] for request in requests: print request if not requestIDs: return S_ERROR( 'No requests selected for conditions: %s' % conditions ) else: return result ############################################################################# def getRequestSummary( self, printOutput = False ): """ Get a summary of the requests in the request DB. """ requestClient = RPCClient( "RequestManagement/centralURL", timeout = 120 ) result = requestClient.getDBSummary() if not result['OK']: self.log.warn( result['Message'] ) return result if printOutput: print self.pPrint.pformat( result['Value'] ) return result ############################################################################# def getExternalPackageVersions( self ): """ Simple function that attempts to obtain the external versions for the local DIRAC installation (frequently needed for debugging purposes). """ gLogger.info( 'DIRAC version v%dr%d build %d' % ( DIRAC.majorVersion, DIRAC.minorVersion, DIRAC.patchLevel ) ) try: import lcg_util infoStr = 'Using lcg_util from: \n%s' % lcg_util.__file__ gLogger.info( infoStr ) infoStr = "The version of lcg_utils is %s" % lcg_util.lcg_util_version() gLogger.info( infoStr ) except Exception as x: errStr = "SRM2Storage.__init__: Failed to import lcg_util: %s" % ( x ) gLogger.exception( errStr ) try: import gfalthr as gfal infoStr = "Using gfalthr from: \n%s" % gfal.__file__ gLogger.info( infoStr ) infoStr = "The version of gfalthr is %s" % gfal.gfal_version() gLogger.info( infoStr ) except Exception as x: errStr = "SRM2Storage.__init__: Failed to import gfalthr: %s." % ( x ) gLogger.warn( errStr ) try: import gfal infoStr = "Using gfal from: %s" % gfal.__file__ gLogger.info( infoStr ) infoStr = "The version of gfal is %s" % gfal.gfal_version() gLogger.info( infoStr ) except Exception as x: errStr = "SRM2Storage.__init__: Failed to import gfal: %s" % ( x ) gLogger.exception( errStr ) defaultProtocols = gConfig.getValue( '/Resources/StorageElements/DefaultProtocols', [] ) gLogger.info( 'Default list of protocols are: %s' % ( ', '.join( defaultProtocols ) ) ) return S_OK() ############################################################################# def getSiteProtocols( self, site, printOutput = False ): """ Allows to check the defined protocols for each site SE. """ result = self.__checkSiteIsValid( site ) if not result['OK']: return result siteSection = '/Resources/Sites/%s/%s/SE' % ( site.split( '.' )[0], site ) siteSEs = gConfig.getValue( siteSection, [] ) if not siteSEs: return S_ERROR( 'No SEs found for site %s in section %s' % ( site, siteSection ) ) defaultProtocols = gConfig.getValue( '/Resources/StorageElements/DefaultProtocols', [] ) self.log.verbose( 'Default list of protocols are' ', '.join( defaultProtocols ) ) seInfo = {} siteSEs.sort() for se in siteSEs: sections = gConfig.getSections( '/Resources/StorageElements/%s/' % ( se ) ) if not sections['OK']: return sections for section in sections['Value']: if gConfig.getValue( '/Resources/StorageElements/%s/%s/ProtocolName' % ( se, section ), '' ) == 'SRM2': path = '/Resources/StorageElements/%s/%s/ProtocolsList' % ( se, section ) seProtocols = gConfig.getValue( path, [] ) if not seProtocols: seProtocols = defaultProtocols seInfo[se] = seProtocols if printOutput: print '\nSummary of protocols for StorageElements at site %s' % site print '\nStorageElement'.ljust( 30 ) + 'ProtocolsList'.ljust( 30 ) + '\n' for se, protocols in seInfo.iteritems(): print se.ljust( 30 ) + ', '.join( protocols ).ljust( 30 ) return S_OK( seInfo ) ############################################################################# def setSiteProtocols( self, site, protocolsList, printOutput = False ): """ Allows to set the defined protocols for each SE for a given site. """ result = self.__checkSiteIsValid( site ) if not result['OK']: return result siteSection = '/Resources/Sites/%s/%s/SE' % ( site.split( '.' )[0], site ) siteSEs = gConfig.getValue( siteSection, [] ) if not siteSEs: return S_ERROR( 'No SEs found for site %s in section %s' % ( site, siteSection ) ) defaultProtocols = gConfig.getValue( '/Resources/StorageElements/DefaultProtocols', [] ) self.log.verbose( 'Default list of protocols are', ', '.join( defaultProtocols ) ) for protocol in protocolsList: if not protocol in defaultProtocols: return S_ERROR( 'Requested to set protocol %s in list but %s is not ' 'in default list of protocols:\n%s' % ( protocol, protocol, ', '.join( defaultProtocols ) ) ) modifiedCS = False result = promptUser( 'Do you want to add the following default protocols:' ' %s for SE(s):\n%s' % ( ', '.join( protocolsList ), ', '.join( siteSEs ) ) ) if not result['OK']: return result if result['Value'].lower() != 'y': self.log.always( 'No protocols will be added' ) return S_OK() for se in siteSEs: sections = gConfig.getSections( '/Resources/StorageElements/%s/' % ( se ) ) if not sections['OK']: return sections for section in sections['Value']: if gConfig.getValue( '/Resources/StorageElements/%s/%s/ProtocolName' % ( se, section ), '' ) == 'SRM2': path = '/Resources/StorageElements/%s/%s/ProtocolsList' % ( se, section ) self.log.verbose( 'Setting %s to %s' % ( path, ', '.join( protocolsList ) ) ) result = self.csSetOption( path, ', '.join( protocolsList ) ) if not result['OK']: return result modifiedCS = True if modifiedCS: result = self.csCommitChanges( False ) if not result[ 'OK' ]: return S_ERROR( 'CS Commit failed with message = %s' % ( result[ 'Message' ] ) ) else: if printOutput: print 'Successfully committed changes to CS' else: if printOutput: print 'No modifications to CS required' return S_OK() ############################################################################# def csSetOption( self, optionPath, optionValue ): """ Function to modify an existing value in the CS. """ return self.csAPI.setOption( optionPath, optionValue ) ############################################################################# def csSetOptionComment( self, optionPath, comment ): """ Function to modify an existing value in the CS. """ return self.csAPI.setOptionComment( optionPath, comment ) ############################################################################# def csModifyValue( self, optionPath, newValue ): """ Function to modify an existing value in the CS. """ return self.csAPI.modifyValue( optionPath, newValue ) ############################################################################# def csRegisterUser( self, username, properties ): """ Registers a user in the CS. - username: Username of the user (easy;) - properties: Dict containing: - DN - groups : list/tuple of groups the user belongs to - <others> : More properties of the user, like mail """ return self.csAPI.addUser( username, properties ) ############################################################################# def csDeleteUser( self, user ): """ Deletes a user from the CS. Can take a list of users """ return self.csAPI.deleteUsers( user ) ############################################################################# def csModifyUser( self, username, properties, createIfNonExistant = False ): """ Modify a user in the CS. Takes the same params as in addUser and applies the changes """ return self.csAPI.modifyUser( username, properties, createIfNonExistant ) ############################################################################# def csListUsers( self, group = False ): """ Lists the users in the CS. If no group is specified return all users. """ return self.csAPI.listUsers( group ) ############################################################################# def csDescribeUsers( self, mask = False ): """ List users and their properties in the CS. If a mask is given, only users in the mask will be returned """ return self.csAPI.describeUsers( mask ) ############################################################################# def csModifyGroup( self, groupname, properties, createIfNonExistant = False ): """ Modify a user in the CS. Takes the same params as in addGroup and applies the changes """ return self.csAPI.modifyGroup( groupname, properties, createIfNonExistant ) ############################################################################# def csListHosts( self ): """ Lists the hosts in the CS """ return self.csAPI.listHosts() ############################################################################# def csDescribeHosts( self, mask = False ): """ Gets extended info for the hosts in the CS """ return self.csAPI.describeHosts( mask ) ############################################################################# def csModifyHost( self, hostname, properties, createIfNonExistant = False ): """ Modify a host in the CS. Takes the same params as in addHost and applies the changes """ return self.csAPI.modifyHost( hostname, properties, createIfNonExistant ) ############################################################################# def csListGroups( self ): """ Lists groups in the CS """ return self.csAPI.listGroups() ############################################################################# def csDescribeGroups( self, mask = False ): """ List groups and their properties in the CS. If a mask is given, only groups in the mask will be returned """ return self.csAPI.describeGroups( mask ) ############################################################################# def csSyncUsersWithCFG( self, usersCFG ): """ Synchronize users in cfg with its contents """ return self.csAPI.syncUsersWithCFG( usersCFG ) ############################################################################# def csCommitChanges( self, sortUsers = True ): """ Commit the changes in the CS """ return self.csAPI.commitChanges( sortUsers = False ) ############################################################################# def sendMail( self, address, subject, body, fromAddress = None, localAttempt = True, html = False ): """ Send mail to specified address with body. """ notification = NotificationClient() return notification.sendMail( address, subject, body, fromAddress, localAttempt, html ) ############################################################################# def sendSMS( self, userName, body, fromAddress = None ): """ Send mail to specified address with body. """ if len( body ) > 160: return S_ERROR( 'Exceeded maximum SMS length of 160 characters' ) notification = NotificationClient() return notification.sendSMS( userName, body, fromAddress ) ############################################################################# def getBDIISite( self, site, host = None ): """ Get information about site from BDII at host """ return ldapSite( site, host = host ) ############################################################################# def getBDIICluster( self, ce, host = None ): """ Get information about ce from BDII at host """ return ldapCluster( ce, host = host ) ############################################################################# def getBDIICE( self, ce, host = None ): """ Get information about ce from BDII at host """ return ldapCE( ce, host = host ) ############################################################################# def getBDIIService( self, ce, host = None ): """ Get information about ce from BDII at host """ return ldapService( ce, host = host ) ############################################################################# def getBDIICEState( self, ce, useVO = voName, host = None ): """ Get information about ce state from BDII at host """ return ldapCEState( ce, useVO, host = host ) ############################################################################# def getBDIICEVOView( self, ce, useVO = voName, host = None ): """ Get information about ce voview from BDII at host """ return ldapCEVOView( ce, useVO, host = host ) ############################################################################# def getBDIISE( self, site, useVO = voName, host = None ): """ Get information about SA from BDII at host """ return ldapSE( site, useVO, host = host )
class CE2CSAgent( AgentModule ): addressTo = '' addressFrom = '' voName = '' subject = "CE2CSAgent" alternativeBDIIs = [] def initialize( self ): # TODO: Have no default and if no mail is found then use the diracAdmin group # and resolve all associated mail addresses. self.addressTo = self.am_getOption( 'MailTo', self.addressTo ) self.addressFrom = self.am_getOption( 'MailFrom', self.addressFrom ) # create a list of alternative bdii urls self.alternativeBDIIs = self.am_getOption( 'AlternativeBDIIs', [] ) # check if the bdii url is appended by a port number, if not append the default 2170 for index, url in enumerate( self.alternativeBDIIs ): if not url.split( ':' )[-1].isdigit(): self.alternativeBDIIs[index] += ':2170' if self.addressTo and self.addressFrom: self.log.info( "MailTo", self.addressTo ) self.log.info( "MailFrom", self.addressFrom ) if self.alternativeBDIIs : self.log.info( "AlternativeBDII URLs:", self.alternativeBDIIs ) self.subject = "CE2CSAgent" # This sets the Default Proxy to used as that defined under # /Operations/Shifter/TestManager # the shifterProxy option in the Configuration can be used to change this default. self.am_setOption( 'shifterProxy', 'TestManager' ) self.voName = self.am_getOption( 'VirtualOrganization', self.voName ) if not self.voName: self.voName = getVO() if not self.voName: self.log.fatal( "VO option not defined for agent" ) return S_ERROR() self.csAPI = CSAPI() return self.csAPI.initialize() def execute( self ): self.log.info( "Start Execution" ) result = getProxyInfo() if not result[ 'OK' ]: return result infoDict = result[ 'Value' ] self.log.info( formatProxyInfoAsString( infoDict ) ) #Get a "fresh" copy of the CS data result = self.csAPI.downloadCSData() if not result[ 'OK' ]: self.log.warn( "Could not download a fresh copy of the CS data", result[ 'Message' ] ) self.__lookForCE() self.__infoFromCE() self.log.info( "End Execution" ) return S_OK() def __checkAlternativeBDIISite( self, fun, *args ): if self.alternativeBDIIs: self.log.warn( "Trying to use alternative bdii sites" ) for site in self.alternativeBDIIs : self.log.info( "Trying to contact alternative bdii ", site ) if len( args ) == 1 : result = fun( args[0], host = site ) elif len( args ) == 2 : result = fun( args[0], vo = args[1], host = site ) if not result['OK'] : self.log.error ( "Problem contacting alternative bddii", result['Message'] ) elif result['OK'] : return result self.log.warn( "Also checking alternative BDII sites failed" ) return result def __lookForCE( self ): knownces = self.am_getOption( 'BannedCEs', [] ) result = gConfig.getSections( '/Resources/Sites' ) if not result['OK']: return grids = result['Value'] for grid in grids: result = gConfig.getSections( '/Resources/Sites/%s' % grid ) if not result['OK']: return sites = result['Value'] for site in sites: opt = gConfig.getOptionsDict( '/Resources/Sites/%s/%s' % ( grid, site ) )['Value'] ces = List.fromChar( opt.get( 'CE', '' ) ) knownces += ces response = ldapCEState( '', vo = self.voName ) if not response['OK']: self.log.error( "Error during BDII request", response['Message'] ) response = self.__checkAlternativeBDIISite( ldapCEState, '', self.voName ) return response newces = {} for queue in response['Value']: try: queuename = queue['GlueCEUniqueID'] except: continue cename = queuename.split( ":" )[0] if not cename in knownces: newces[cename] = None self.log.debug( "newce", cename ) body = "" possibleNewSites = [] for ce in newces.iterkeys(): response = ldapCluster( ce ) if not response['OK']: self.log.warn( "Error during BDII request", response['Message'] ) response = self.__checkAlternativeBDIISite( ldapCluster, ce ) continue clusters = response['Value'] if len( clusters ) != 1: self.log.warn( "Error in cluster length", " CE %s Length %d" % ( ce, len( clusters ) ) ) if len( clusters ) == 0: continue cluster = clusters[0] fkey = cluster.get( 'GlueForeignKey', [] ) if type( fkey ) == type( '' ): fkey = [fkey] nameBDII = None for entry in fkey: if entry.count( 'GlueSiteUniqueID' ): nameBDII = entry.split( '=' )[1] break if not nameBDII: continue cestring = "CE: %s, GOCDB Name: %s" % ( ce, nameBDII ) self.log.info( cestring ) response = ldapCE( ce ) if not response['OK']: self.log.warn( "Error during BDII request", response['Message'] ) response = self.__checkAlternativeBDIISite( ldapCE, ce ) continue ceinfos = response['Value'] if len( ceinfos ): ceinfo = ceinfos[0] systemName = ceinfo.get( 'GlueHostOperatingSystemName', 'Unknown' ) systemVersion = ceinfo.get( 'GlueHostOperatingSystemVersion', 'Unknown' ) systemRelease = ceinfo.get( 'GlueHostOperatingSystemRelease', 'Unknown' ) else: systemName = "Unknown" systemVersion = "Unknown" systemRelease = "Unknown" osstring = "SystemName: %s, SystemVersion: %s, SystemRelease: %s" % ( systemName, systemVersion, systemRelease ) self.log.info( osstring ) response = ldapCEState( ce, vo = self.voName ) if not response['OK']: self.log.warn( "Error during BDII request", response['Message'] ) response = self.__checkAlternativeBDIISite( ldapCEState, ce, self.voName ) continue newcestring = "\n\n%s\n%s" % ( cestring, osstring ) usefull = False cestates = response['Value'] for cestate in cestates: queuename = cestate.get( 'GlueCEUniqueID', 'UnknownName' ) queuestatus = cestate.get( 'GlueCEStateStatus', 'UnknownStatus' ) queuestring = "%s %s" % ( queuename, queuestatus ) self.log.info( queuestring ) newcestring += "\n%s" % queuestring if queuestatus.count( 'Production' ): usefull = True if usefull: body += newcestring possibleNewSites.append( 'dirac-admin-add-site DIRACSiteName %s %s' % ( nameBDII, ce ) ) if body: body = "We are glad to inform You about new CE(s) possibly suitable for %s:\n" % self.voName + body body += "\n\nTo suppress information about CE add its name to BannedCEs list." for possibleNewSite in possibleNewSites: body = "%s\n%s" % ( body, possibleNewSite ) self.log.info( body ) if self.addressTo and self.addressFrom: notification = NotificationClient() result = notification.sendMail( self.addressTo, self.subject, body, self.addressFrom, localAttempt = False ) return S_OK() def __infoFromCE( self ): sitesSection = cfgPath( 'Resources', 'Sites' ) result = gConfig.getSections( sitesSection ) if not result['OK']: return grids = result['Value'] changed = False body = "" for grid in grids: gridSection = cfgPath( sitesSection, grid ) result = gConfig.getSections( gridSection ) if not result['OK']: return sites = result['Value'] for site in sites: siteSection = cfgPath( gridSection, site ) opt = gConfig.getOptionsDict( siteSection )['Value'] name = opt.get( 'Name', '' ) if name: coor = opt.get( 'Coordinates', 'Unknown' ) mail = opt.get( 'Mail', 'Unknown' ) result = ldapSite( name ) if not result['OK']: self.log.warn( "BDII site %s: %s" % ( name, result['Message'] ) ) result = self.__checkAlternativeBDIISite( ldapSite, name ) if result['OK']: bdiisites = result['Value'] if len( bdiisites ) == 0: self.log.warn( name, "Error in bdii: leng = 0" ) else: if not len( bdiisites ) == 1: self.log.warn( name, "Warning in bdii: leng = %d" % len( bdiisites ) ) bdiisite = bdiisites[0] try: longitude = bdiisite['GlueSiteLongitude'] latitude = bdiisite['GlueSiteLatitude'] newcoor = "%s:%s" % ( longitude, latitude ) except: self.log.warn( "Error in bdii coor" ) newcoor = "Unknown" try: newmail = bdiisite['GlueSiteSysAdminContact'].split( ":" )[-1].strip() except: self.log.warn( "Error in bdii mail" ) newmail = "Unknown" self.log.debug( "%s %s %s" % ( name, newcoor, newmail ) ) if newcoor != coor: self.log.info( "%s" % ( name ), "%s -> %s" % ( coor, newcoor ) ) if coor == 'Unknown': self.csAPI.setOption( cfgPath( siteSection, 'Coordinates' ), newcoor ) else: self.csAPI.modifyValue( cfgPath( siteSection, 'Coordinates' ), newcoor ) changed = True if newmail != mail: self.log.info( "%s" % ( name ), "%s -> %s" % ( mail, newmail ) ) if mail == 'Unknown': self.csAPI.setOption( cfgPath( siteSection, 'Mail' ), newmail ) else: self.csAPI.modifyValue( cfgPath( siteSection, 'Mail' ), newmail ) changed = True celist = List.fromChar( opt.get( 'CE', '' ) ) if not celist: self.log.warn( site, 'Empty site list' ) continue # result = gConfig.getSections( cfgPath( siteSection,'CEs' ) # if not result['OK']: # self.log.debug( "Section CEs:", result['Message'] ) for ce in celist: ceSection = cfgPath( siteSection, 'CEs', ce ) result = gConfig.getOptionsDict( ceSection ) if not result['OK']: self.log.debug( "Section CE", result['Message'] ) wnTmpDir = 'Unknown' arch = 'Unknown' os = 'Unknown' si00 = 'Unknown' pilot = 'Unknown' cetype = 'Unknown' else: ceopt = result['Value'] wnTmpDir = ceopt.get( 'wnTmpDir', 'Unknown' ) arch = ceopt.get( 'architecture', 'Unknown' ) os = ceopt.get( 'OS', 'Unknown' ) si00 = ceopt.get( 'SI00', 'Unknown' ) pilot = ceopt.get( 'Pilot', 'Unknown' ) cetype = ceopt.get( 'CEType', 'Unknown' ) result = ldapCE( ce ) if not result['OK']: self.log.warn( 'Error in bdii for %s' % ce, result['Message'] ) result = self.__checkAlternativeBDIISite( ldapCE, ce ) continue try: bdiice = result['Value'][0] except: self.log.warn( 'Error in bdii for %s' % ce, result ) bdiice = None if bdiice: try: newwnTmpDir = bdiice['GlueSubClusterWNTmpDir'] except: newwnTmpDir = 'Unknown' if wnTmpDir != newwnTmpDir and newwnTmpDir != 'Unknown': section = cfgPath( ceSection, 'wnTmpDir' ) self.log.info( section, " -> ".join( ( wnTmpDir, newwnTmpDir ) ) ) if wnTmpDir == 'Unknown': self.csAPI.setOption( section, newwnTmpDir ) else: self.csAPI.modifyValue( section, newwnTmpDir ) changed = True try: newarch = bdiice['GlueHostArchitecturePlatformType'] except: newarch = 'Unknown' if arch != newarch and newarch != 'Unknown': section = cfgPath( ceSection, 'architecture' ) self.log.info( section, " -> ".join( ( arch, newarch ) ) ) if arch == 'Unknown': self.csAPI.setOption( section, newarch ) else: self.csAPI.modifyValue( section, newarch ) changed = True try: newos = '_'.join( ( bdiice['GlueHostOperatingSystemName'], bdiice['GlueHostOperatingSystemVersion'], bdiice['GlueHostOperatingSystemRelease'] ) ) except: newos = 'Unknown' if os != newos and newos != 'Unknown': section = cfgPath( ceSection, 'OS' ) self.log.info( section, " -> ".join( ( os, newos ) ) ) if os == 'Unknown': self.csAPI.setOption( section, newos ) else: self.csAPI.modifyValue( section, newos ) changed = True body = body + "OS was changed %s -> %s for %s at %s\n" % ( os, newos, ce, site ) try: newsi00 = bdiice['GlueHostBenchmarkSI00'] except: newsi00 = 'Unknown' if si00 != newsi00 and newsi00 != 'Unknown': section = cfgPath( ceSection, 'SI00' ) self.log.info( section, " -> ".join( ( si00, newsi00 ) ) ) if si00 == 'Unknown': self.csAPI.setOption( section, newsi00 ) else: self.csAPI.modifyValue( section, newsi00 ) changed = True try: rte = bdiice['GlueHostApplicationSoftwareRunTimeEnvironment'] if self.voName.lower() == 'lhcb': if 'VO-lhcb-pilot' in rte: newpilot = 'True' else: newpilot = 'False' else: newpilot = 'Unknown' except: newpilot = 'Unknown' if pilot != newpilot and newpilot != 'Unknown': section = cfgPath( ceSection, 'Pilot' ) self.log.info( section, " -> ".join( ( pilot, newpilot ) ) ) if pilot == 'Unknown': self.csAPI.setOption( section, newpilot ) else: self.csAPI.modifyValue( section, newpilot ) changed = True result = ldapCEState( ce, vo = self.voName ) #getBDIICEVOView if not result['OK']: self.log.warn( 'Error in bdii for queue %s' % ce, result['Message'] ) result = self.__checkAlternativeBDIISite( ldapCEState, ce, self.voName ) continue try: queues = result['Value'] except: self.log.warn( 'Error in bdii for queue %s' % ce, result['Massage'] ) continue newcetype = 'Unknown' for queue in queues: try: queuetype = queue['GlueCEImplementationName'] except: queuetype = 'Unknown' if newcetype == 'Unknown': newcetype = queuetype else: if queuetype != newcetype: self.log.warn( 'Error in bdii for ce %s ' % ce, 'different cetypes %s %s' % ( newcetype, queuetype ) ) if newcetype=='ARC-CE': newcetype = 'ARC' if cetype != newcetype and newcetype != 'Unknown': section = cfgPath( ceSection, 'CEType' ) self.log.info( section, " -> ".join( ( cetype, newcetype ) ) ) if cetype == 'Unknown': self.csAPI.setOption( section, newcetype ) else: self.csAPI.modifyValue( section, newcetype ) changed = True for queue in queues: try: queueName = queue['GlueCEUniqueID'].split( '/' )[-1] except: self.log.warn( 'error in queuename ', queue ) continue try: newmaxCPUTime = queue['GlueCEPolicyMaxCPUTime'] except: newmaxCPUTime = None newsi00 = None try: caps = queue['GlueCECapability'] if type( caps ) == type( '' ): caps = [caps] for cap in caps: if cap.count( 'CPUScalingReferenceSI00' ): newsi00 = cap.split( '=' )[-1] except: newsi00 = None queueSection = cfgPath( ceSection, 'Queues', queueName ) result = gConfig.getOptionsDict( queueSection ) if not result['OK']: self.log.warn( "Section Queues", result['Message'] ) maxCPUTime = 'Unknown' si00 = 'Unknown' else: queueopt = result['Value'] maxCPUTime = queueopt.get( 'maxCPUTime', 'Unknown' ) si00 = queueopt.get( 'SI00', 'Unknown' ) if newmaxCPUTime and ( maxCPUTime != newmaxCPUTime ): section = cfgPath( queueSection, 'maxCPUTime' ) self.log.info( section, " -> ".join( ( maxCPUTime, newmaxCPUTime ) ) ) if maxCPUTime == 'Unknown': self.csAPI.setOption( section, newmaxCPUTime ) else: self.csAPI.modifyValue( section, newmaxCPUTime ) changed = True if newsi00 and ( si00 != newsi00 ): section = cfgPath( queueSection, 'SI00' ) self.log.info( section, " -> ".join( ( si00, newsi00 ) ) ) if si00 == 'Unknown': self.csAPI.setOption( section, newsi00 ) else: self.csAPI.modifyValue( section, newsi00 ) changed = True if changed: self.log.info( body ) if body and self.addressTo and self.addressFrom: notification = NotificationClient() result = notification.sendMail( self.addressTo, self.subject, body, self.addressFrom, localAttempt = False ) return self.csAPI.commit() else: self.log.info( "No changes found" ) return S_OK()
userName = res['Value']['username'] group = res['Value']['group'] if not sites: Script.showHelp() DIRAC.exit( -1 ) catalogCFGBase = "/Resources/FileCatalogs/LcgFileCatalogCombined" banned = [] for site in sites: res = gConfig.getOptionsDict( '%s/%s' % ( catalogCFGBase, site ) ) if not res['OK']: gLogger.error( "The provided site (%s) does not have an associated catalog." % site ) continue res = csAPI.setOption( "%s/%s/Status" % ( storageCFGBase, site ), "InActive" ) if not res['OK']: gLogger.error( "Failed to update %s catalog status to InActive" % site ) else: gLogger.debug( "Successfully updated %s catalog status to InActive" % site ) banned.append( site ) if not banned: gLogger.error( "Failed to ban any catalog mirrors" ) DIRAC.exit( -1 ) res = csAPI.commitChanges() if not res['OK']: gLogger.error( "Failed to commit changes to CS", res['Message'] ) DIRAC.exit( -1 )
gLogger.error("Number out of range: %d" % inp) DIRACExit(-1) else: diracCSSite = result["Value"][0] if diracCSSite == diracSiteName: gLogger.notice("Site with GOC name %s is already defined as %s" % (gridSiteName, diracSiteName)) newSite = False else: gLogger.error("ERROR: Site with GOC name %s is already defined as %s" % (gridSiteName, diracCSSite)) DIRACExit(-1) cfgBase = "/Resources/Sites/%s/%s" % (diracGridType, diracSiteName) change = False if newSite: gLogger.notice("Adding new site to CS: %s" % diracSiteName) csAPI.setOption("%s/Name" % cfgBase, gridSiteName) gLogger.notice("Adding CEs: %s" % ",".join(ces)) csAPI.setOption("%s/CE" % cfgBase, ",".join(ces)) change = True else: cesCS = set(gConfig.getValue("%s/CE" % cfgBase, [])) ces = set(ces) newCEs = ces - cesCS if newCEs: cesCS = cesCS.union(ces) gLogger.notice("Adding CEs %s" % ",".join(newCEs)) cesCS = cesCS.union(ces) csAPI.modifyValue("%s/CE" % cfgBase, ",".join(cesCS)) change = True if change: res = csAPI.commitChanges()
if diracCSSite == diracSiteName: gLogger.notice( 'Site with GOC name %s is already defined as %s' % (gridSiteName, diracSiteName)) newSite = False else: gLogger.error( 'ERROR: Site with GOC name %s is already defined as %s' % (gridSiteName, diracCSSite)) DIRACExit(-1) cfgBase = "/Resources/Sites/%s/%s" % (diracGridType, diracSiteName) change = False if newSite: gLogger.notice("Adding new site to CS: %s" % diracSiteName) csAPI.setOption("%s/Name" % cfgBase, gridSiteName) gLogger.notice("Adding CEs: %s" % ','.join(ces)) csAPI.setOption("%s/CE" % cfgBase, ','.join(ces)) change = True else: cesCS = set(gConfig.getValue("%s/CE" % cfgBase, [])) ces = set(ces) newCEs = ces - cesCS if newCEs: cesCS = cesCS.union(ces) gLogger.notice("Adding CEs %s" % ','.join(newCEs)) cesCS = cesCS.union(ces) csAPI.modifyValue("%s/CE" % cfgBase, ','.join(cesCS)) change = True if change: res = csAPI.commitChanges()
Script.parseCommandLine() args = Script.getPositionalArgs() setupName = args[0] # Where to store outputs if not os.path.isdir( '%s/sandboxes' % setupName ): os.makedirs( '%s/sandboxes' % setupName ) # now updating the CS from DIRAC.ConfigurationSystem.Client.CSAPI import CSAPI csAPI = CSAPI() csAPI.setOption( 'Systems/WorkloadManagement/Production/Services/SandboxStore/BasePath', '%s/sandboxes' % setupName ) csAPI.setOption( 'Systems/WorkloadManagement/Production/Services/SandboxStore/LogLevel', 'DEBUG' ) # Now setting a SandboxSE as the following: # ProductionSandboxSE # { # BackendType = DISET # AccessProtocol.1 # { # Host = localhost # Port = 9196 # ProtocolName = DIP # Protocol = dips # Path = /scratch/workspace/%s/sandboxes % setupName # Access = remote # SpaceToken =
def checkUnusedSEs(): global vo, dry result = getGridSRMs(vo, unUsed=True) if not result["OK"]: gLogger.error("Failed to look up SRMs in BDII", result["Message"]) siteSRMDict = result["Value"] # Evaluate VOs result = getVOs() if result["OK"]: csVOs = set(result["Value"]) else: csVOs = {vo} changeSetFull = set() for site in siteSRMDict: for gridSE in siteSRMDict[site]: changeSet = set() seDict = siteSRMDict[site][gridSE]["SE"] srmDict = siteSRMDict[site][gridSE]["SRM"] # Check the SRM version version = srmDict.get("GlueServiceVersion", "") if not (version and version.startswith("2")): gLogger.debug("Skipping SRM service with version %s" % version) continue result = getDIRACSiteName(site) if not result["OK"]: gLogger.notice("Unused se %s is detected at unused site %s" % (gridSE, site)) gLogger.notice("Consider adding site %s to the DIRAC CS" % site) continue diracSites = result["Value"] yn = raw_input( "\nDo you want to add new SRM SE %s at site(s) %s ? default yes [yes|no]: " % (gridSE, str(diracSites)) ) if not yn or yn.lower().startswith("y"): if len(diracSites) > 1: prompt = "Which DIRAC site the new SE should be attached to ?" for i, s in enumerate(diracSites): prompt += "\n[%d] %s" % (i, s) prompt += "\nEnter your choice number: " inp = raw_input(prompt) try: ind = int(inp) except: gLogger.notice("Can not interpret your choice: %s, try again later" % inp) continue diracSite = diracSites[ind] else: diracSite = diracSites[0] domain, siteName, country = diracSite.split(".") recName = "%s-disk" % siteName inp = raw_input("Give a DIRAC name to the grid SE %s, default %s : " % (gridSE, recName)) diracSEName = inp if not inp: diracSEName = recName gLogger.notice("Adding new SE %s at site %s" % (diracSEName, diracSite)) seSection = cfgPath("/Resources/StorageElements", diracSEName) changeSet.add((seSection, "BackendType", seDict.get("GlueSEImplementationName", "Unknown"))) changeSet.add((seSection, "Description", seDict.get("GlueSEName", "Unknown"))) bdiiVOs = set( [re.sub("^VO:", "", rule) for rule in srmDict.get("GlueServiceAccessControlBaseRule", [])] ) seVOs = csVOs.intersection(bdiiVOs) changeSet.add((seSection, "VO", ",".join(seVOs))) accessSection = cfgPath(seSection, "AccessProtocol.1") changeSet.add((accessSection, "Protocol", "srm")) changeSet.add((accessSection, "PluginName", "SRM2")) endPoint = srmDict.get("GlueServiceEndpoint", "") host = urlparse(endPoint).hostname port = urlparse(endPoint).port changeSet.add((accessSection, "Host", host)) changeSet.add((accessSection, "Port", port)) changeSet.add((accessSection, "Access", "remote")) voPathSection = cfgPath(accessSection, "VOPath") if "VOPath" in seDict: path = seDict["VOPath"] voFromPath = os.path.basename(path) if voFromPath != diracVO: gLogger.notice("\n!!! Warning: non-conventional VO path: %s\n" % path) changeSet.add((voPathSection, diracVO, path)) path = os.path.dirname(path) else: # Try to guess the Path domain = ".".join(host.split(".")[-2:]) path = "/dpm/%s/home" % domain changeSet.add((accessSection, "Path", path)) changeSet.add((accessSection, "SpaceToken", "")) changeSet.add((accessSection, "WSUrl", "/srm/managerv2?SFN=")) gLogger.notice("SE %s will be added with the following parameters" % diracSEName) changeList = list(changeSet) changeList.sort() for entry in changeList: gLogger.notice(entry) yn = raw_input("Do you want to add new SE %s ? default yes [yes|no]: " % diracSEName) if not yn or yn.lower().startswith("y"): changeSetFull = changeSetFull.union(changeSet) if dry: if changeSetFull: gLogger.notice("Skipping commit of the new SE data in a dry run") else: gLogger.notice("No new SE to be added") return S_OK() if changeSetFull: csAPI = CSAPI() csAPI.initialize() result = csAPI.downloadCSData() if not result["OK"]: gLogger.error("Failed to initialize CSAPI object", result["Message"]) DIRACExit(-1) changeList = list(changeSetFull) changeList.sort() for section, option, value in changeList: csAPI.setOption(cfgPath(section, option), value) yn = raw_input("New SE data is accumulated\n Do you want to commit changes to CS ? default yes [yes|no]: ") if not yn or yn.lower().startswith("y"): result = csAPI.commit() if not result["OK"]: gLogger.error("Error while commit to CS", result["Message"]) else: gLogger.notice("Successfully committed %d changes to CS" % len(changeSetFull)) else: gLogger.notice("No new SE to be added") return S_OK()