Exemplo n.º 1
0
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 ) )  
Exemplo n.º 2
0
  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
Exemplo n.º 3
0
  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()
Exemplo n.º 5
0
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
Exemplo n.º 6
0
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()
Exemplo n.º 7
0
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']:
Exemplo n.º 8
0
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()
Exemplo n.º 10
0
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
Exemplo n.º 11
0
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
Exemplo n.º 12
0
#         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()
Exemplo n.º 13
0
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()
Exemplo n.º 15
0
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()
Exemplo n.º 17
0
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)
Exemplo n.º 18
0
#!/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)
Exemplo n.º 19
0
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
Exemplo n.º 20
0
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()
Exemplo n.º 22
0
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 )
Exemplo n.º 24
0
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,
    }
Exemplo n.º 25
0
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()
Exemplo n.º 27
0
#         {
#           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()
Exemplo n.º 28
0
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)
Exemplo n.º 29
0
# }


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 =
Exemplo n.º 30
0
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
Exemplo n.º 31
0
  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'] )
Exemplo n.º 32
0
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)
Exemplo n.º 33
0
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
Exemplo n.º 34
0
        "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)
Exemplo n.º 35
0
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()
Exemplo n.º 36
0
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 )
Exemplo n.º 37
0
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()
Exemplo n.º 38
0
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 )
Exemplo n.º 39
0
                    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()
Exemplo n.º 40
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()
Exemplo n.º 41
0
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 =
Exemplo n.º 42
0
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()