Beispiel #1
0
 def __assignSandboxesToJob(self, jobID, classAdJob):
     sandboxClient = SandboxStoreClient()
     inputSandboxes = self.__getInputSandboxEntries(classAdJob)
     sbToAssign = []
     for isb in inputSandboxes:
         if isb.find("SB:") == 0:
             sbToAssign.append(isb)
     if sbToAssign:
         assignList = [(isb, 'Input') for isb in sbToAssign]
         result = sandboxClient.assignSandboxesToJob(jobID, assignList)
         if not result['OK']:
             return result
     return S_OK()
Beispiel #2
0
 def __assignSandboxesToJob( self, jobID, classAdJob ):
   sandboxClient = SandboxStoreClient()
   inputSandboxes = self.__getInputSandboxEntries( classAdJob )
   sbToAssign = []
   for isb in inputSandboxes:
     if isb.find( "SB:" ) == 0:
       sbToAssign.append( isb )
   if sbToAssign:
     assignList = [ ( isb, 'Input' ) for isb in sbToAssign ]
     result = sandboxClient.assignSandboxesToJob( jobID, assignList )
     if not result[ 'OK' ]:
       return result
   return S_OK()
Beispiel #3
0
class JobSanityAgent( OptimizerModule ):
  """
      The specific Optimizer must provide the following methods:
      - checkJob() - the main method called for each job
      and it can provide:
      - initializeOptimizer() before each execution cycle      
  """

  #############################################################################
  def initializeOptimizer( self ):
    """Initialize specific parameters for JobSanityAgent.
    """
    #Test control flags N.B. JDL check is mandatory
    self.inputDataCheck = self.am_getOption( 'InputDataCheck', 1 )
    self.outputDataCheck = self.am_getOption( 'OutputDataCheck', 0 )
    self.inputSandboxCheck = self.am_getOption( 'InputSandboxCheck', 1 )
    self.platformCheck = self.am_getOption( 'PlatformCheck', 0 )
    #Other parameters
    self.voName = getVO( 'lhcb' )
    self.successStatus = self.am_getOption( 'SuccessfulJobStatus', 'OutputReady' )
    self.maxDataPerJob = self.am_getOption( 'MaxInputDataPerJob', 100 )
    #Sandbox
    self.sandboxClient = SandboxStoreClient( useCertificates = True )

    self.log.debug( 'JDL Check          ==>  Enabled' )
    if self.inputDataCheck:
      self.log.debug( 'Input Data Check   ==>  Enabled' )
    else:
      self.log.debug( 'Input Data Check   ==>  Disabled' )
    if self.outputDataCheck:
      self.log.debug( 'Output Data Check  ==>  Enabled' )
    else:
      self.log.debug( 'Output Data Check  ==>  Disabled' )
    if self.inputSandboxCheck:
      self.log.debug( 'Input Sbox Check   ==>  Enabled' )
    else:
      self.log.debug( 'Input Sbox Check   ==>  Disabled' )
    if self.platformCheck:
      self.log.debug( 'Platform Check     ==>  Enabled' )
    else:
      self.log.debug( 'Platform Check     ==>  Disabled' )

    return S_OK()

  #############################################################################
  def checkJob( self, job, classAdJob ):
    """ This method controls the order and presence of
        each sanity check for submitted jobs. This should
        be easily extended in the future to accommodate
        any other potential checks.
    """
    #Job JDL check
    message = "Job: %s JDL: OK," % job
    self.log.debug( "Checking Loop Starts for job %s" % job )

    jobType = self.jobDB.getJobAttribute( job, 'JobType' )
    if not jobType['OK']:
      return S_ERROR( 'Could not determine job type' )
    jobType = jobType['Value']

    #Input data check
    if self.inputDataCheck:
      inputData = self.checkInputData( job, jobType )
      if inputData['OK']:
        number = inputData['Value']
        message += 'InputData: ' + number + ', '
      else:
        minorStatus = inputData['Value']
        self.log.info( message )
        self.log.info( 'Job: ' + str( job ) + ' Failed input data check.' )
        return S_ERROR( minorStatus )

    #Platform check # disabled
    if self.platformCheck:
      platform = self.checkPlatformSupported( job, classAdJob )
      if platform['OK']:
        arch = platform['Value']
        message += 'Platform: ' + arch + ' OK, '
      else:
        res = 'No supported platform for job ' + str( job ) + '.'
        minorStatus = platform['Value']
        self.log.info( message )
        self.log.info( res )
        return S_ERROR( message )

    #Output data exists check
    if self.outputDataCheck: # disabled
      if jobType != 'user':
        outputData = self.checkOutputDataExists( job, classAdJob )
        if outputData['OK']:
          if outputData.has_key( 'SUCCESS' ):
            success = self.successStatus
            minorStatus = outputData['SUCCESS']
            report = outputData['Value']
            message += report
            self.log.info( message )
            self.setJobParam( job, 'JobSanityCheck', message )
            self.updateJobStatus( job, success, minorStatus )
            # FIXME: this can not be a S_OK(), Job has to be aborted if OutPut data is present
            return S_OK( 'Found successful job' )
          else:
            flag = outputData['Value']
            message += 'Output Data: ' + flag + ', '
        else:
          res = 'Job: ' + str( job ) + ' Failed since output data exists.'
          minorStatus = outputData['Value']
          self.log.info( message )
          self.log.info( res )
          return S_ERROR( message )

    #Input Sandbox uploaded check
    if self.inputSandboxCheck: # disabled
      inputSandbox = self.checkInputSandbox( job, classAdJob )
      if inputSandbox['OK']:
        sbChecked = inputSandbox['Value']
        message += ' Input Sandboxes: %s, OK.' % sbChecked
      else:
        res = 'Job: %s failed due some missing sandboxes' % job
        minorStatus = inputSandbox['Message']
        self.log.info( message )
        self.log.info( res )
        return S_ERROR( minorStatus )

    self.log.info( message )
    self.setJobParam( job, 'JobSanityCheck', message )
    return self.setNextOptimizer( job )

  #############################################################################
  def checkInputData( self, job, jobType ):
    """This method checks both the amount of input
       datasets for the job and whether the LFN conventions
       are correct.
    """
    voName = self.voName
    maxData = int( self.maxDataPerJob )
    totalData = 0
    slashFlag = 0
    incorrectDataFlag = 0

    result = self.jobDB.getInputData( job )

    if not result['OK']:
      self.log.warn( 'Failed to get input data from JobDB for %s' % ( job ) )
      self.log.warn( result['Message'] )
      result = S_ERROR()
      result['Value'] = 'Input Data Specification'
      return result

    if not result['Value']:
      return S_OK( 'No input LFNs' )

    data = result['Value'] # seems to be [''] when null, which isn't an empty list ;)
    ok = False
    for i in data:
      if i:
        ok = True
    if not ok:
      self.log.debug( 'Job %s has no input data requirement' % ( job ) )
      return S_OK( 'No input LFNs' )

    self.log.debug( 'Job %s has an input data requirement and will be checked' % ( job ) )
    data = result['Value']
    repData = '\n'
    for i in data:
      repData += i + '\n'
    self.log.debug( 'Data is: %s' % ( repData ) )

    totalData = len( data )

    if totalData:
      for i in data:
        j = i.replace( 'LFN:', '' )
        if not re.search( '^/' + voName + '/', j ):
          incorrectDataFlag += 1
        if re.search( '//', j ):
          slashFlag += 1

    if incorrectDataFlag:
      result = S_ERROR()
      result['Value'] = "Input data not correctly specified"
      return result

    if slashFlag:
      result = S_ERROR()
      result['Value'] = "Input data contains //"
      return result

    #only check limit for user jobs
    if jobType.lower() == 'user' and totalData > maxData:
      message = '%s datasets selected. Max limit is %s.' % ( totalData, maxData )
      self.setJobParam( job, 'DatasetCheck', message )
      result = S_ERROR()
      result['Value'] = "Exceeded Maximum Dataset Limit (%s)" % ( maxData )
      return result

    number = str( totalData )
    result = S_OK()
    result['Value'] = number + ' LFNs OK'
    return result

  #############################################################################
  def  checkOutputDataExists( self, job, classAdJob ):
    """If the job output data is already in the LFC, this
       method will fail the job for the attention of the
       data manager. To be tidied for DIRAC3...
    """
    # FIXME: To implement checkOutputDataExists
    return S_OK()

  #############################################################################
  def checkPlatformSupported( self, job, classAdJob ):
    """This method queries the CS for available platforms
       supported by DIRAC and will check these against what
       the job requests.
    """
    # FIXME: To implement checkPlatformSupported
    return S_OK()

  #############################################################################
  def checkInputSandbox( self, job, classAdJob ):
    """The number of input sandbox files, as specified in the job
       JDL are checked in the JobDB.
    """
    ownerName = classAdJob.getAttributeString( "Owner" )
    if not ownerName:
      ownerDN = classAdJob.getAttributeString( "OwnerDN" )
      ownerName = CS.getUsernameForDN( ownerDN )
    ownerGroup = classAdJob.getAttributeString( "OwnerGroup" )
    jobSetup = classAdJob.getAttributeString( "DIRACSetup" )
    isbList = classAdJob.getListFromExpression( 'InputSandbox' )
    sbsToAssign = []
    for isb in isbList:
      if isb.find( "SB:" ) == 0:
        self.log.info( "Found a sandbox", isb )
        sbsToAssign.append( ( isb, "Input" ) )
    numSBsToAssign = len( sbsToAssign )
    if not numSBsToAssign:
      return S_OK( 0 )
    self.log.info( "Assigning %s sandboxes on behalf of %s@%s" % ( numSBsToAssign, ownerName, ownerGroup ) )
    result = self.sandboxClient.assignSandboxesToJob( job, sbsToAssign, ownerName, ownerGroup, jobSetup )
    if not result[ 'OK' ]:
      self.log.error( "Could not assign sandboxes in the SandboxStore", "assigned to job %s" % job )
      return S_ERROR( "Cannot assign sandbox to job" )
    assigned = result[ 'Value' ]
    if assigned != numSBsToAssign:
      self.log.error( "Could not assign all sandboxes (%s). Only assigned %s" % ( numSBsToAssign, assigned ) )
    return S_OK( numSBsToAssign )
Beispiel #4
0
class JobSanityAgent( OptimizerModule ):
  """
      The specific Optimizer must provide the following methods:
      - checkJob() - the main method called for each job
      and it can provide:
      - initializeOptimizer() before each execution cycle      
  """

  #############################################################################
  def initializeOptimizer( self ):
    """Initialize specific parameters for JobSanityAgent.
    """
    #Test control flags N.B. JDL check is mandatory
    self.inputDataCheck = self.am_getOption( 'InputDataCheck', 1 )
    self.outputDataCheck = self.am_getOption( 'OutputDataCheck', 0 )
    self.inputSandboxCheck = self.am_getOption( 'InputSandboxCheck', 1 )
    self.platformCheck = self.am_getOption( 'PlatformCheck', 0 )
    #Other parameters
    self.successStatus = self.am_getOption( 'SuccessfulJobStatus', 'OutputReady' )
    self.maxDataPerJob = self.am_getOption( 'MaxInputDataPerJob', 100 )
    #Sandbox
    self.sandboxClient = SandboxStoreClient( useCertificates = True )

    self.log.debug( 'JDL Check          ==>  Enabled' )
    if self.inputDataCheck:
      self.log.debug( 'Input Data Check   ==>  Enabled' )
    else:
      self.log.debug( 'Input Data Check   ==>  Disabled' )
    if self.outputDataCheck:
      self.log.debug( 'Output Data Check  ==>  Enabled' )
    else:
      self.log.debug( 'Output Data Check  ==>  Disabled' )
    if self.inputSandboxCheck:
      self.log.debug( 'Input Sbox Check   ==>  Enabled' )
    else:
      self.log.debug( 'Input Sbox Check   ==>  Disabled' )
    if self.platformCheck:
      self.log.debug( 'Platform Check     ==>  Enabled' )
    else:
      self.log.debug( 'Platform Check     ==>  Disabled' )

    return S_OK()

  #############################################################################
  def checkJob( self, job, classAdJob ):
    """ This method controls the order and presence of
        each sanity check for submitted jobs. This should
        be easily extended in the future to accommodate
        any other potential checks.
    """
    #Job JDL check
    message = "Job: %s JDL: OK," % job
    self.log.debug( "Checking Loop Starts for job %s" % job )

    jobType = self.jobDB.getJobAttribute( job, 'JobType' )
    if not jobType['OK']:
      return S_ERROR( 'Could not determine job type' )
    jobType = jobType['Value']

    #Input data check
    if self.inputDataCheck:
      voName = classAdJob.getAttributeString( "VirtualOrganization" )
      inputData = self.checkInputData( job, jobType, voName )
      if inputData['OK']:
        number = inputData['Value']
        message += 'InputData: ' + number + ', '
      else:
        minorStatus = inputData['Value']
        self.log.info( message )
        self.log.info( 'Job: ' + str( job ) + ' Failed input data check.' )
        return S_ERROR( minorStatus )

    #Platform check # disabled
    if self.platformCheck:
      platform = self.checkPlatformSupported( job, classAdJob )
      if platform['OK']:
        arch = platform['Value']
        message += 'Platform: ' + arch + ' OK, '
      else:
        res = 'No supported platform for job ' + str( job ) + '.'
        minorStatus = platform['Value']
        self.log.info( message )
        self.log.info( res )
        return S_ERROR( message )

    #Output data exists check
    if self.outputDataCheck: # disabled
      if jobType != 'user':
        outputData = self.checkOutputDataExists( job, classAdJob )
        if outputData['OK']:
          if outputData.has_key( 'SUCCESS' ):
            success = self.successStatus
            minorStatus = outputData['SUCCESS']
            report = outputData['Value']
            message += report
            self.log.info( message )
            self.setJobParam( job, 'JobSanityCheck', message )
            self.updateJobStatus( job, success, minorStatus )
            # FIXME: this can not be a S_OK(), Job has to be aborted if OutPut data is present
            return S_OK( 'Found successful job' )
          else:
            flag = outputData['Value']
            message += 'Output Data: ' + flag + ', '
        else:
          res = 'Job: ' + str( job ) + ' Failed since output data exists.'
          minorStatus = outputData['Value']
          self.log.info( message )
          self.log.info( res )
          return S_ERROR( message )

    #Input Sandbox uploaded check
    if self.inputSandboxCheck: # disabled
      inputSandbox = self.checkInputSandbox( job, classAdJob )
      if inputSandbox['OK']:
        sbChecked = inputSandbox['Value']
        message += ' Input Sandboxes: %s, OK.' % sbChecked
      else:
        res = 'Job: %s failed due some missing sandboxes' % job
        minorStatus = inputSandbox['Message']
        self.log.info( message )
        self.log.info( res )
        return S_ERROR( minorStatus )

    self.log.info( message )
    self.setJobParam( job, 'JobSanityCheck', message )
    return self.setNextOptimizer( job )

  #############################################################################
  def checkInputData( self, job, jobType, voName ):
    """This method checks both the amount of input
       datasets for the job and whether the LFN conventions
       are correct.
    """
    maxData = int( self.maxDataPerJob )
    totalData = 0
    slashFlag = 0
    incorrectDataFlag = 0

    result = self.jobDB.getInputData( job )

    if not result['OK']:
      self.log.warn( 'Failed to get input data from JobDB for %s' % ( job ) )
      self.log.warn( result['Message'] )
      result = S_ERROR()
      result['Value'] = 'Input Data Specification'
      return result

    if not result['Value']:
      return S_OK( 'No input LFNs' )

    data = result['Value'] # seems to be [''] when null, which isn't an empty list ;)
    ok = False
    for i in data:
      if i:
        ok = True
    if not ok:
      self.log.debug( 'Job %s has no input data requirement' % ( job ) )
      return S_OK( 'No input LFNs' )

    self.log.debug( 'Job %s has an input data requirement and will be checked' % ( job ) )
    data = result['Value']
    repData = '\n'
    for i in data:
      repData += i + '\n'
    self.log.debug( 'Data is: %s' % ( repData ) )

    totalData = len( data )

    if totalData:
      for i in data:
        j = i.replace( 'LFN:', '' )
        if not re.search( '^/' + voName + '/', j ):
          incorrectDataFlag += 1
        if re.search( '//', j ):
          slashFlag += 1

    if incorrectDataFlag:
      result = S_ERROR()
      result['Value'] = "Input data not correctly specified"
      return result

    if slashFlag:
      result = S_ERROR()
      result['Value'] = "Input data contains //"
      return result

    #only check limit for user jobs
    if jobType.lower() == 'user' and totalData > maxData:
      message = '%s datasets selected. Max limit is %s.' % ( totalData, maxData )
      self.setJobParam( job, 'DatasetCheck', message )
      result = S_ERROR()
      result['Value'] = "Exceeded Maximum Dataset Limit (%s)" % ( maxData )
      return result

    number = str( totalData )
    result = S_OK()
    result['Value'] = number + ' LFNs OK'
    return result

  #############################################################################
  def  checkOutputDataExists( self, job, classAdJob ):
    """If the job output data is already in the LFC, this
       method will fail the job for the attention of the
       data manager. To be tidied for DIRAC3...
    """
    # FIXME: To implement checkOutputDataExists
    return S_OK()

  #############################################################################
  def checkPlatformSupported( self, job, classAdJob ):
    """This method queries the CS for available platforms
       supported by DIRAC and will check these against what
       the job requests.
    """
    # FIXME: To implement checkPlatformSupported
    return S_OK()

  #############################################################################
  def checkInputSandbox( self, job, classAdJob ):
    """The number of input sandbox files, as specified in the job
       JDL are checked in the JobDB.
    """
    ownerName = classAdJob.getAttributeString( "Owner" )
    if not ownerName:
      ownerDN = classAdJob.getAttributeString( "OwnerDN" )
      ownerName = CS.getUsernameForDN( ownerDN )
    ownerGroup = classAdJob.getAttributeString( "OwnerGroup" )
    jobSetup = classAdJob.getAttributeString( "DIRACSetup" )
    isbList = classAdJob.getListFromExpression( 'InputSandbox' )
    sbsToAssign = []
    for isb in isbList:
      if isb.find( "SB:" ) == 0:
        self.log.info( "Found a sandbox", isb )
        sbsToAssign.append( ( isb, "Input" ) )
    numSBsToAssign = len( sbsToAssign )
    if not numSBsToAssign:
      return S_OK( 0 )
    self.log.info( "Assigning %s sandboxes on behalf of %s@%s" % ( numSBsToAssign, ownerName, ownerGroup ) )
    result = self.sandboxClient.assignSandboxesToJob( job, sbsToAssign, ownerName, ownerGroup, jobSetup )
    if not result[ 'OK' ]:
      self.log.error( "Could not assign sandboxes in the SandboxStore", "assigned to job %s" % job )
      return S_ERROR( "Cannot assign sandbox to job" )
    assigned = result[ 'Value' ]
    if assigned != numSBsToAssign:
      self.log.error( "Could not assign all sandboxes (%s). Only assigned %s" % ( numSBsToAssign, assigned ) )
    return S_OK( numSBsToAssign )