def execute( self ):
    """ execute
    
    """

    stopAgents = self.findStopAgents()[ 'Value' ]
    if stopAgents:
      self.log.info( 'Aborting, there are stop_agents to be picked' )
      return S_OK()

    pilotVersion = self.opHelper.getValue( 'Pilot/Version', '' )
    if not pilotVersion:
      self.log.error( 'There is no pilot version on the CS' )
      return S_OK()

    pilotVersion = self.getNewestPilotVersion()
    if not pilotVersion[ 'OK' ]:
      self.log.error( pilotVersion[ 'Message' ] )
      return S_ERROR( pilotVersion[ 'Message' ] )
    pilotVersion = pilotVersion[ 'Value' ]
      
    localCFG = CFG()
    
    #load local CFG
    localCFG.loadFromFile( self.cfgToUpdate )
    releaseVersion = localCFG.getRecursive( 'LocalSite/ReleaseVersion' )[ 'value' ]
    
    self.log.info( 'PilotVersion : %s' % pilotVersion )
    self.log.info( 'ReleaseVersion : %s' % releaseVersion )
            
    if LooseVersion( pilotVersion ) > LooseVersion( releaseVersion ):
    
      self.log.info( 'UPDATING %s > %s' % ( pilotVersion, releaseVersion ) )
    
      localCFG.setOption( 'LocalSite/ReleaseVersion', pilotVersion )
      localCFG.writeToFile( self.cfgToUpdate )  
      
      self.touchStopAgents()
    
    else:
      
      self.log.info( 'Nothing to do' )
    
    return S_OK()     
Example #2
0
class JobManifest(object):
    def __init__(self, manifest=""):
        self.__manifest = CFG()
        self.__dirty = False
        self.__ops = False
        if manifest:
            result = self.load(manifest)
            if not result["OK"]:
                raise Exception(result["Message"])

    def isDirty(self):
        return self.__dirty

    def setDirty(self):
        self.__dirty = True

    def clearDirty(self):
        self.__dirty = False

    def load(self, dataString):
        """
    Auto discover format type based on [ .. ] of JDL
    """
        dataString = dataString.strip()
        if dataString[0] == "[" and dataString[-1] == "]":
            return self.loadJDL(dataString)
        else:
            return self.loadCFG(dataString)

    def loadJDL(self, jdlString):
        """
    Load job manifest from JDL format
    """
        result = loadJDLAsCFG(jdlString.strip())
        if not result["OK"]:
            self.__manifest = CFG()
            return result
        self.__manifest = result["Value"][0]
        return S_OK()

    def loadCFG(self, cfgString):
        """
    Load job manifest from CFG format
    """
        try:
            self.__manifest.loadFromBuffer(cfgString)
        except Exception as e:
            return S_ERROR("Can't load manifest from cfg: %s" % str(e))
        return S_OK()

    def dumpAsCFG(self):
        return str(self.__manifest)

    def getAsCFG(self):
        return self.__manifest.clone()

    def dumpAsJDL(self):
        return dumpCFGAsJDL(self.__manifest)

    def __getCSValue(self, varName, defaultVal=None):
        if not self.__ops:
            self.__ops = Operations(group=self.__manifest["OwnerGroup"], setup=self.__manifest["DIRACSetup"])
        if varName[0] != "/":
            varName = "JobDescription/%s" % varName
        return self.__ops.getValue(varName, defaultVal)

    def __checkNumericalVar(self, varName, defaultVal, minVal, maxVal):
        """
    Check a numerical var
    """
        initialVal = False
        if varName not in self.__manifest:
            varValue = self.__getCSValue("Default%s" % varName, defaultVal)
        else:
            varValue = self.__manifest[varName]
            initialVal = varValue
        try:
            varValue = long(varValue)
        except:
            return S_ERROR("%s must be a number" % varName)
        minVal = self.__getCSValue("Min%s" % varName, minVal)
        maxVal = self.__getCSValue("Max%s" % varName, maxVal)
        varValue = max(minVal, min(varValue, maxVal))
        if initialVal != varValue:
            self.__manifest.setOption(varName, varValue)
        return S_OK(varValue)

    def __checkChoiceVar(self, varName, defaultVal, choices):
        """
    Check a choice var
    """
        initialVal = False
        if varName not in self.__manifest:
            varValue = self.__getCSValue("Default%s" % varName, defaultVal)
        else:
            varValue = self.__manifest[varName]
            initialVal = varValue
        if varValue not in self.__getCSValue("Choices%s" % varName, choices):
            return S_ERROR("%s is not a valid value for %s" % (varValue, varName))
        if initialVal != varValue:
            self.__manifest.setOption(varName, varValue)
        return S_OK(varValue)

    def __checkMultiChoice(self, varName, choices):
        """
    Check a multi choice var
    """
        initialVal = False
        if varName not in self.__manifest:
            return S_OK()
        else:
            varValue = self.__manifest[varName]
            initialVal = varValue
        choices = self.__getCSValue("Choices%s" % varName, choices)
        for v in List.fromChar(varValue):
            if v not in choices:
                return S_ERROR("%s is not a valid value for %s" % (v, varName))
        if initialVal != varValue:
            self.__manifest.setOption(varName, varValue)
        return S_OK(varValue)

    def __checkMaxInputData(self, maxNumber):
        """
    Check Maximum Number of Input Data files allowed
    """
        varName = "InputData"
        if varName not in self.__manifest:
            return S_OK()
        varValue = self.__manifest[varName]
        if len(List.fromChar(varValue)) > maxNumber:
            return S_ERROR(
                "Number of Input Data Files (%s) greater than current limit: %s"
                % (len(List.fromChar(varValue)), maxNumber)
            )
        return S_OK()

    def __contains__(self, key):
        """ Check if the manifest has the required key
    """
        return key in self.__manifest

    def setOptionsFromDict(self, varDict):
        for k in sorted(varDict):
            self.setOption(k, varDict[k])

    def check(self):
        """
    Check that the manifest is OK
    """
        for k in ["OwnerName", "OwnerDN", "OwnerGroup", "DIRACSetup"]:
            if k not in self.__manifest:
                return S_ERROR("Missing var %s in manifest" % k)

        # Check CPUTime
        result = self.__checkNumericalVar("CPUTime", 86400, 100, 500000)
        if not result["OK"]:
            return result

        result = self.__checkNumericalVar("Priority", 1, 0, 10)
        if not result["OK"]:
            return result

        allowedSubmitPools = getSubmitPools(self.__manifest["OwnerGroup"])
        result = self.__checkMultiChoice("SubmitPools", list(set(allowedSubmitPools)))
        if not result["OK"]:
            return result

        result = self.__checkMultiChoice("PilotTypes", ["private"])
        if not result["OK"]:
            return result

        maxInputData = Operations().getValue("JobDescription/MaxInputData", 500)
        result = self.__checkMaxInputData(maxInputData)
        if not result["OK"]:
            return result

        transformationTypes = Operations().getValue("Transformations/DataProcessing", [])
        result = self.__checkMultiChoice("JobType", ["User", "Test", "Hospital"] + transformationTypes)
        if not result["OK"]:
            return result
        return S_OK()

    def createSection(self, secName, contents=False):
        if secName not in self.__manifest:
            if contents and not isinstance(contents, CFG):
                return S_ERROR("Contents for section %s is not a cfg object" % secName)
            self.__dirty = True
            return S_OK(self.__manifest.createNewSection(secName, contents=contents))
        return S_ERROR("Section %s already exists" % secName)

    def getSection(self, secName):
        self.__dirty = True
        sec = self.__manifest[secName]
        if not sec:
            return S_ERROR("%s does not exist")
        return S_OK(sec)

    def setSectionContents(self, secName, contents):
        if contents and not isinstance(contents, CFG):
            return S_ERROR("Contents for section %s is not a cfg object" % secName)
        self.__dirty = True
        if secName in self.__manifest:
            self.__manifest[secName].reset()
            self.__manifest[secName].mergeWith(contents)
        else:
            self.__manifest.createNewSection(secName, contents=contents)

    def setOption(self, varName, varValue):
        """
    Set a var in job manifest
    """
        self.__dirty = True
        levels = List.fromChar(varName, "/")
        cfg = self.__manifest
        for l in levels[:-1]:
            if l not in cfg:
                cfg.createNewSection(l)
            cfg = cfg[l]
        cfg.setOption(levels[-1], varValue)

    def remove(self, opName):
        levels = List.fromChar(opName, "/")
        cfg = self.__manifest
        for l in levels[:-1]:
            if l not in cfg:
                return S_ERROR("%s does not exist" % opName)
            cfg = cfg[l]
        if cfg.deleteKey(levels[-1]):
            self.__dirty = True
            return S_OK()
        return S_ERROR("%s does not exist" % opName)

    def getOption(self, varName, defaultValue=None):
        """
     Get a variable from the job manifest
    """
        cfg = self.__manifest
        return cfg.getOption(varName, defaultValue)

    def getOptionList(self, section=""):
        """
    Get a list of variables in a section of the job manifest
    """
        cfg = self.__manifest.getRecursive(section)
        if not cfg or "value" not in cfg:
            return []
        cfg = cfg["value"]
        return cfg.listOptions()

    def isOption(self, opName):
        """
    Check if it is a valid option
    """
        return self.__manifest.isOption(opName)

    def getSectionList(self, section=""):
        """
    Get a list of sections in the job manifest
    """
        cfg = self.__manifest.getRecursive(section)
        if not cfg or "value" not in cfg:
            return []
        cfg = cfg["value"]
        return cfg.listSections()
Example #3
0
class Modificator:

  def __init__( self, rpcClient = False, commiterId = "unknown" ):
    self.commiterTag = "@@-"
    self.commiterId = commiterId
    self.cfgData = CFG()
    self.rpcClient = None
    if rpcClient:
      self.setRPCClient( rpcClient )

  def loadCredentials( self ):
    retVal = getProxyInfo()
    if retVal[ 'OK' ]:
      credDict = retVal[ 'Value' ]
      self.commiterId = "%s@%s - %s" % ( credDict[ 'username' ],
                                         credDict[ 'group' ],
                                         Time.dateTime().strftime( "%Y-%m-%d %H:%M:%S" ) )
      return retVal
    return retVal

  def setRPCClient( self, rpcClient ):
    self.rpcClient = rpcClient

  def loadFromRemote( self ):
    retVal = self.rpcClient.getCompressedData()
    if retVal[ 'OK' ]:
      self.cfgData = CFG()
      self.cfgData.loadFromBuffer( zlib.decompress( retVal[ 'Value' ] ) )
    return retVal

  def getCFG( self ):
    return self.cfgData

  def getSections( self, sectionPath ):
    return gConfigurationData.getSectionsFromCFG( sectionPath, self.cfgData )

  def getComment( self, sectionPath ):
    return gConfigurationData.getCommentFromCFG( sectionPath, self.cfgData )

  def getOptions( self, sectionPath ):
    return gConfigurationData.getOptionsFromCFG( sectionPath, self.cfgData )

  def getOptionsDict(self, sectionPath):
    """Gives the options of a CS section in a Python dict with values as
    lists"""

    opts = self.getOptions(sectionPath)
    pathDict = dict( ( o, self.getValue( "%s/%s" % ( sectionPath, o ) ) ) for o in opts )
    return pathDict

  def getDictRootedAt(self, relpath = "", root = ""):
    """Gives the configuration rooted at path in a Python dict. The
    result is a Python dictionary that reflects the structure of the
    config file."""
    def getDictRootedAt(path):
      retval = {}
      opts = self.getOptionsDict(path)
      secs = self.getSections(path)
      for k in opts:
        retval[k] = opts[k]
      for i in secs:
        retval[i] = getDictRootedAt(path + "/" + i)
      return retval

    return getDictRootedAt(root + "/" + relpath)

  def getValue( self, optionPath ):
    return gConfigurationData.extractOptionFromCFG( optionPath, self.cfgData )

  def sortAlphabetically( self, path, ascending = True ):
    cfg = self.__getParentCFG( path, parentLevel = 0 )
    if cfg:
      if cfg.sortAlphabetically( ascending ):
        self.__setCommiter( path )

  def __getParentCFG( self, path, parentLevel = 1 ):
    sectionList = List.fromChar( path, "/" )
    cfg = self.cfgData
    try:
      if parentLevel > 0:
        sectionList = sectionList[:-parentLevel]
      for section in sectionList:
        cfg = cfg[ section ]
      return cfg
    except:
      return False

  def __setCommiter( self, entryPath, cfg = False ):
    if not cfg:
      cfg = self.__getParentCFG( entryPath )
    entry = List.fromChar( entryPath, "/" )[-1]
    comment = cfg.getComment( entry )
    filteredComment = [ line.strip() for line in comment.split( "\n" ) if line.find( self.commiterTag ) != 0 ]
    filteredComment.append( "%s%s" % ( self.commiterTag, self.commiterId ) )
    cfg.setComment( entry, "\n".join( filteredComment ) )

  def setOptionValue( self, optionPath, value ):
    levelList = [ level.strip() for level in optionPath.split( "/" ) if level.strip() != "" ]
    parentPath = "/%s" % "/".join( levelList[:-1] )
    optionName = List.fromChar( optionPath, "/" )[-1]
    self.createSection( parentPath )
    cfg = self.__getParentCFG( optionPath )
    if not cfg:
      return
    cfg.setOption( optionName, value )
    self.__setCommiter( optionPath, cfg )

  def createSection( self, sectionPath ):
    levelList = [ level.strip() for level in sectionPath.split( "/" ) if level.strip() != "" ]
    currentPath = ""
    cfg = self.cfgData
    createdSection = False
    for section in levelList:
      currentPath += "/%s" % section
      if section not in cfg.listSections():
        cfg.createNewSection( section )
        self.__setCommiter( currentPath )
        createdSection = True
      cfg = cfg[ section ]
    return createdSection

  def setComment( self, entryPath, value ):
    cfg = self.__getParentCFG( entryPath )
    entry = List.fromChar( entryPath, "/" )[-1]
    if cfg.setComment( entry, value ):
      self.__setCommiter( entryPath )
      return True
    return False

  def existsSection( self, sectionPath ):
    sectionList = List.fromChar( sectionPath, "/" )
    cfg = self.cfgData
    try:
      for section in sectionList[:-1]:
        cfg = cfg[ section ]
      return len( sectionList ) == 0 or sectionList[-1] in cfg.listSections()
    except:
      return False

  def existsOption( self, optionPath ):
    sectionList = List.fromChar( optionPath, "/" )
    cfg = self.cfgData
    try:
      for section in sectionList[:-1]:
        cfg = cfg[ section ]
      return sectionList[-1] in cfg.listOptions()
    except:
      return False

  def renameKey( self, path, newName ):
    parentCfg = self.cfgData.getRecursive( path, -1 )
    if not parentCfg:
      return False
    pathList = List.fromChar( path, "/" )
    oldName = pathList[-1]
    if parentCfg[ 'value' ].renameKey( oldName, newName ):
      pathList[-1] = newName
      self.__setCommiter( "/%s" % "/".join( pathList ) )
      return True
    else:
      return False

  def copyKey( self, originalKeyPath, newKey ):
    parentCfg = self.cfgData.getRecursive( originalKeyPath, -1 )
    if not parentCfg:
      return False
    pathList = List.fromChar( originalKeyPath, "/" )
    originalKey = pathList[-1]
    if parentCfg[ 'value' ].copyKey( originalKey, newKey ):
      self.__setCommiter( "/%s/%s" % ( "/".join( pathList[:-1] ), newKey ) )
      return True
    return False

  def removeOption( self, optionPath ):
    if not self.existsOption( optionPath ):
      return False
    cfg = self.__getParentCFG( optionPath )
    optionName = List.fromChar( optionPath, "/" )[-1]
    return cfg.deleteKey( optionName )

  def removeSection( self, sectionPath ):
    if not self.existsSection( sectionPath ):
      return False
    cfg = self.__getParentCFG( sectionPath )
    sectionName = List.fromChar( sectionPath, "/" )[-1]
    return cfg.deleteKey( sectionName )

  def loadFromBuffer( self, data ):
    self.cfgData = CFG()
    self.cfgData.loadFromBuffer( data )

  def loadFromFile( self, filename ):
    self.cfgData = CFG()
    self.mergeFromFile( filename )

  def dumpToFile( self, filename ):
    fd = file( filename, "w" )
    fd.write( str( self.cfgData ) )
    fd.close()

  def mergeFromFile( self, filename ):
    cfg = CFG()
    cfg.loadFromFile( filename )
    self.cfgData = self.cfgData.mergeWith( cfg )

  def mergeFromCFG( self, cfg ):
    self.cfgData = self.cfgData.mergeWith( cfg )

  def mergeSectionFromCFG( self, sectionPath, cfg ):
    parentDict = self.cfgData.getRecursive( sectionPath, -1 )
    parentCFG = parentDict[ 'value' ]
    secName = [ lev.strip() for lev in sectionPath.split( "/" ) if lev.strip() ][-1]
    secCFG = parentCFG[ secName ]
    if not secCFG:
      return False
    mergedCFG = secCFG.mergeWith( cfg )
    parentCFG.deleteKey( secName )
    parentCFG.createNewSection( secName, parentDict[ 'comment' ], mergedCFG )
    self.__setCommiter( sectionPath )
    return True

  def __str__( self ):
    return str( self.cfgData )

  def commit( self ):
    compressedData = zlib.compress( str( self.cfgData ), 9 )
    return self.rpcClient.commitNewData( compressedData )

  def getHistory( self, limit = 0 ):
    retVal = self.rpcClient.getCommitHistory( limit )
    if retVal[ 'OK' ]:
      return retVal[ 'Value' ]
    return []

  def showCurrentDiff( self ):
    retVal = self.rpcClient.getCompressedData()
    if retVal[ 'OK' ]:
      remoteData = zlib.decompress( retVal[ 'Value' ] ).splitlines()
      localData = str( self.cfgData ).splitlines()
      return difflib.ndiff( remoteData, localData )
    return []

  def getVersionDiff( self, fromDate, toDate ):
    retVal = self.rpcClient.getVersionContents( [ fromDate, toDate ] )
    if retVal[ 'OK' ]:
      fromData = zlib.decompress( retVal[ 'Value' ][0] )
      toData = zlib.decompress( retVal[ 'Value' ][1] )
      return difflib.ndiff( fromData.split( "\n" ), toData.split( "\n" ) )
    return []

  def mergeWithServer( self ):
    retVal = self.rpcClient.getCompressedData()
    if retVal[ 'OK' ]:
      remoteCFG = CFG()
      remoteCFG.loadFromBuffer( zlib.decompress( retVal[ 'Value' ] ) )
      serverVersion = gConfigurationData.getVersion( remoteCFG )
      self.cfgData = remoteCFG.mergeWith( self.cfgData )
      gConfigurationData.setVersion( serverVersion, self.cfgData )
    return retVal

  def rollbackToVersion( self, version ):
    return self.rpcClient.rollbackToVersion( version )

  def updateGConfigurationData( self ):
    gConfigurationData.setRemoteCFG( self.cfgData )
Example #4
0
class Modificator( object ):

  def __init__( self, rpcClient = False, commiterId = "unknown" ):
    self.commiterTag = "@@-"
    self.commiterId = commiterId
    self.cfgData = CFG()
    self.rpcClient = None
    if rpcClient:
      self.setRPCClient( rpcClient )

  def loadCredentials( self ):
    retVal = getProxyInfo()
    if retVal[ 'OK' ]:
      credDict = retVal[ 'Value' ]
      self.commiterId = "%s@%s - %s" % ( credDict[ 'username' ],
                                         credDict[ 'group' ],
                                         Time.dateTime().strftime( "%Y-%m-%d %H:%M:%S" ) )
      return retVal
    return retVal

  def setRPCClient( self, rpcClient ):
    self.rpcClient = rpcClient

  def loadFromRemote( self ):
    retVal = self.rpcClient.getCompressedData()
    if retVal[ 'OK' ]:
      self.cfgData = CFG()
      self.cfgData.loadFromBuffer( zlib.decompress( retVal[ 'Value' ] ) )
    return retVal

  def getCFG( self ):
    return self.cfgData

  def getSections( self, sectionPath ):
    return gConfigurationData.getSectionsFromCFG( sectionPath, self.cfgData )

  def getComment( self, sectionPath ):
    return gConfigurationData.getCommentFromCFG( sectionPath, self.cfgData )

  def getOptions( self, sectionPath ):
    return gConfigurationData.getOptionsFromCFG( sectionPath, self.cfgData )

  def getOptionsDict(self, sectionPath):
    """Gives the options of a CS section in a Python dict with values as
    lists"""

    opts = self.getOptions(sectionPath)
    pathDict = dict( ( o, self.getValue( "%s/%s" % ( sectionPath, o ) ) ) for o in opts )
    return pathDict

  def getDictRootedAt(self, relpath = "", root = ""):
    """Gives the configuration rooted at path in a Python dict. The
    result is a Python dictionary that reflects the structure of the
    config file."""
    def getDictRootedAt(path):
      retval = {}
      opts = self.getOptionsDict(path)
      secs = self.getSections(path)
      for k in opts:
        retval[k] = opts[k]
      for i in secs:
        retval[i] = getDictRootedAt(path + "/" + i)
      return retval

    return getDictRootedAt(root + "/" + relpath)

  def getValue( self, optionPath ):
    return gConfigurationData.extractOptionFromCFG( optionPath, self.cfgData )

  def sortAlphabetically( self, path, ascending = True ):
    cfg = self.__getParentCFG( path, parentLevel = 0 )
    if cfg:
      if cfg.sortAlphabetically( ascending ):
        self.__setCommiter( path )

  def __getParentCFG( self, path, parentLevel = 1 ):
    sectionList = List.fromChar( path, "/" )
    cfg = self.cfgData
    try:
      if parentLevel > 0:
        sectionList = sectionList[:-parentLevel]
      for section in sectionList:
        cfg = cfg[ section ]
      return cfg
    except:
      return False

  def __setCommiter( self, entryPath, cfg = False ):
    if not cfg:
      cfg = self.__getParentCFG( entryPath )
    entry = List.fromChar( entryPath, "/" )[-1]
    comment = cfg.getComment( entry )
    filteredComment = [ line.strip() for line in comment.split( "\n" ) if line.find( self.commiterTag ) != 0 ]
    filteredComment.append( "%s%s" % ( self.commiterTag, self.commiterId ) )
    cfg.setComment( entry, "\n".join( filteredComment ) )

  def setOptionValue( self, optionPath, value ):
    levelList = [ level.strip() for level in optionPath.split( "/" ) if level.strip() != "" ]
    parentPath = "/%s" % "/".join( levelList[:-1] )
    optionName = List.fromChar( optionPath, "/" )[-1]
    self.createSection( parentPath )
    cfg = self.__getParentCFG( optionPath )
    if not cfg:
      return
    cfg.setOption( optionName, value )
    self.__setCommiter( optionPath, cfg )

  def createSection( self, sectionPath ):
    levelList = [ level.strip() for level in sectionPath.split( "/" ) if level.strip() != "" ]
    currentPath = ""
    cfg = self.cfgData
    createdSection = False
    for section in levelList:
      currentPath += "/%s" % section
      if section not in cfg.listSections():
        cfg.createNewSection( section )
        self.__setCommiter( currentPath )
        createdSection = True
      cfg = cfg[ section ]
    return createdSection

  def setComment( self, entryPath, value ):
    cfg = self.__getParentCFG( entryPath )
    entry = List.fromChar( entryPath, "/" )[-1]
    if cfg.setComment( entry, value ):
      self.__setCommiter( entryPath )
      return True
    return False

  def existsSection( self, sectionPath ):
    sectionList = List.fromChar( sectionPath, "/" )
    cfg = self.cfgData
    try:
      for section in sectionList[:-1]:
        cfg = cfg[ section ]
      return len( sectionList ) == 0 or sectionList[-1] in cfg.listSections()
    except:
      return False

  def existsOption( self, optionPath ):
    sectionList = List.fromChar( optionPath, "/" )
    cfg = self.cfgData
    try:
      for section in sectionList[:-1]:
        cfg = cfg[ section ]
      return sectionList[-1] in cfg.listOptions()
    except:
      return False

  def renameKey( self, path, newName ):
    parentCfg = self.cfgData.getRecursive( path, -1 )
    if not parentCfg:
      return False
    pathList = List.fromChar( path, "/" )
    oldName = pathList[-1]
    if parentCfg[ 'value' ].renameKey( oldName, newName ):
      pathList[-1] = newName
      self.__setCommiter( "/%s" % "/".join( pathList ) )
      return True
    else:
      return False

  def copyKey( self, originalKeyPath, newKey ):
    parentCfg = self.cfgData.getRecursive( originalKeyPath, -1 )
    if not parentCfg:
      return False
    pathList = List.fromChar( originalKeyPath, "/" )
    originalKey = pathList[-1]
    if parentCfg[ 'value' ].copyKey( originalKey, newKey ):
      self.__setCommiter( "/%s/%s" % ( "/".join( pathList[:-1] ), newKey ) )
      return True
    return False

  def removeOption( self, optionPath ):
    if not self.existsOption( optionPath ):
      return False
    cfg = self.__getParentCFG( optionPath )
    optionName = List.fromChar( optionPath, "/" )[-1]
    return cfg.deleteKey( optionName )

  def removeSection( self, sectionPath ):
    if not self.existsSection( sectionPath ):
      return False
    cfg = self.__getParentCFG( sectionPath )
    sectionName = List.fromChar( sectionPath, "/" )[-1]
    return cfg.deleteKey( sectionName )

  def loadFromBuffer( self, data ):
    self.cfgData = CFG()
    self.cfgData.loadFromBuffer( data )

  def loadFromFile( self, filename ):
    self.cfgData = CFG()
    self.mergeFromFile( filename )

  def dumpToFile( self, filename ):
    fd = file( filename, "w" )
    fd.write( str( self.cfgData ) )
    fd.close()

  def mergeFromFile( self, filename ):
    cfg = CFG()
    cfg.loadFromFile( filename )
    self.cfgData = self.cfgData.mergeWith( cfg )

  def mergeFromCFG( self, cfg ):
    self.cfgData = self.cfgData.mergeWith( cfg )

  def mergeSectionFromCFG( self, sectionPath, cfg ):
    parentDict = self.cfgData.getRecursive( sectionPath, -1 )
    parentCFG = parentDict[ 'value' ]
    secName = [ lev.strip() for lev in sectionPath.split( "/" ) if lev.strip() ][-1]
    secCFG = parentCFG[ secName ]
    if not secCFG:
      return False
    mergedCFG = secCFG.mergeWith( cfg )
    parentCFG.deleteKey( secName )
    parentCFG.createNewSection( secName, parentDict[ 'comment' ], mergedCFG )
    self.__setCommiter( sectionPath )
    return True

  def __str__( self ):
    return str( self.cfgData )

  def commit( self ):
    compressedData = zlib.compress( str( self.cfgData ), 9 )
    return self.rpcClient.commitNewData( compressedData )

  def getHistory( self, limit = 0 ):
    retVal = self.rpcClient.getCommitHistory( limit )
    if retVal[ 'OK' ]:
      return retVal[ 'Value' ]
    return []

  def showCurrentDiff( self ):
    retVal = self.rpcClient.getCompressedData()
    if retVal[ 'OK' ]:
      remoteData = zlib.decompress( retVal[ 'Value' ] ).splitlines()
      localData = str( self.cfgData ).splitlines()
      return difflib.ndiff( remoteData, localData )
    return []

  def getVersionDiff( self, fromDate, toDate ):
    retVal = self.rpcClient.getVersionContents( [ fromDate, toDate ] )
    if retVal[ 'OK' ]:
      fromData = zlib.decompress( retVal[ 'Value' ][0] )
      toData = zlib.decompress( retVal[ 'Value' ][1] )
      return difflib.ndiff( fromData.split( "\n" ), toData.split( "\n" ) )
    return []

  def mergeWithServer( self ):
    retVal = self.rpcClient.getCompressedData()
    if retVal[ 'OK' ]:
      remoteCFG = CFG()
      remoteCFG.loadFromBuffer( zlib.decompress( retVal[ 'Value' ] ) )
      serverVersion = gConfigurationData.getVersion( remoteCFG )
      self.cfgData = remoteCFG.mergeWith( self.cfgData )
      gConfigurationData.setVersion( serverVersion, self.cfgData )
    return retVal

  def rollbackToVersion( self, version ):
    return self.rpcClient.rollbackToVersion( version )

  def updateGConfigurationData( self ):
    gConfigurationData.setRemoteCFG( self.cfgData )
Example #5
0
class JobManifest(object):
    def __init__(self, manifest=""):
        self.__manifest = CFG()
        self.__dirty = False
        self.__ops = False
        if manifest:
            result = self.load(manifest)
            if not result['OK']:
                raise Exception(result['Message'])

    def isDirty(self):
        return self.__dirty

    def setDirty(self):
        self.__dirty = True

    def clearDirty(self):
        self.__dirty = False

    def load(self, dataString):
        """
    Auto discover format type based on [ .. ] of JDL
    """
        dataString = dataString.strip()
        if dataString[0] == "[" and dataString[-1] == "]":
            return self.loadJDL(dataString)
        else:
            return self.loadCFG(dataString)

    def loadJDL(self, jdlString):
        """
    Load job manifest from JDL format
    """
        result = loadJDLAsCFG(jdlString.strip())
        if not result['OK']:
            self.__manifest = CFG()
            return result
        self.__manifest = result['Value'][0]
        return S_OK()

    def loadCFG(self, cfgString):
        """
    Load job manifest from CFG format
    """
        try:
            self.__manifest.loadFromBuffer(cfgString)
        except Exception as e:
            return S_ERROR("Can't load manifest from cfg: %s" % str(e))
        return S_OK()

    def dumpAsCFG(self):
        return str(self.__manifest)

    def getAsCFG(self):
        return self.__manifest.clone()

    def dumpAsJDL(self):
        return dumpCFGAsJDL(self.__manifest)

    def __getCSValue(self, varName, defaultVal=None):
        if not self.__ops:
            self.__ops = Operations(group=self.__manifest['OwnerGroup'],
                                    setup=self.__manifest['DIRACSetup'])
        if varName[0] != "/":
            varName = "JobDescription/%s" % varName
        return self.__ops.getValue(varName, defaultVal)

    def __checkNumericalVar(self, varName, defaultVal, minVal, maxVal):
        """
    Check a numerical var
    """
        initialVal = False
        if varName not in self.__manifest:
            varValue = self.__getCSValue("Default%s" % varName, defaultVal)
        else:
            varValue = self.__manifest[varName]
            initialVal = varValue
        try:
            varValue = long(varValue)
        except BaseException:
            return S_ERROR("%s must be a number" % varName)
        minVal = self.__getCSValue("Min%s" % varName, minVal)
        maxVal = self.__getCSValue("Max%s" % varName, maxVal)
        varValue = max(minVal, min(varValue, maxVal))
        if initialVal != varValue:
            self.__manifest.setOption(varName, varValue)
        return S_OK(varValue)

    def __checkChoiceVar(self, varName, defaultVal, choices):
        """
    Check a choice var
    """
        initialVal = False
        if varName not in self.__manifest:
            varValue = self.__getCSValue("Default%s" % varName, defaultVal)
        else:
            varValue = self.__manifest[varName]
            initialVal = varValue
        if varValue not in self.__getCSValue("Choices%s" % varName, choices):
            return S_ERROR("%s is not a valid value for %s" %
                           (varValue, varName))
        if initialVal != varValue:
            self.__manifest.setOption(varName, varValue)
        return S_OK(varValue)

    def __checkMultiChoice(self, varName, choices):
        """
    Check a multi choice var
    """
        initialVal = False
        if varName not in self.__manifest:
            return S_OK()
        else:
            varValue = self.__manifest[varName]
            initialVal = varValue
        choices = self.__getCSValue("Choices%s" % varName, choices)
        for v in List.fromChar(varValue):
            if v not in choices:
                return S_ERROR("%s is not a valid value for %s" % (v, varName))
        if initialVal != varValue:
            self.__manifest.setOption(varName, varValue)
        return S_OK(varValue)

    def __checkMaxInputData(self, maxNumber):
        """
    Check Maximum Number of Input Data files allowed
    """
        varName = "InputData"
        if varName not in self.__manifest:
            return S_OK()
        varValue = self.__manifest[varName]
        if len(List.fromChar(varValue)) > maxNumber:
            return S_ERROR(
                'Number of Input Data Files (%s) greater than current limit: %s'
                % (len(List.fromChar(varValue)), maxNumber))
        return S_OK()

    def __contains__(self, key):
        """ Check if the manifest has the required key
    """
        return key in self.__manifest

    def setOptionsFromDict(self, varDict):
        for k in sorted(varDict):
            self.setOption(k, varDict[k])

    def check(self):
        """
    Check that the manifest is OK
    """
        for k in ['OwnerName', 'OwnerDN', 'OwnerGroup', 'DIRACSetup']:
            if k not in self.__manifest:
                return S_ERROR("Missing var %s in manifest" % k)

        # Check CPUTime
        result = self.__checkNumericalVar("CPUTime", 86400, 100, 500000)
        if not result['OK']:
            return result

        result = self.__checkNumericalVar("Priority", 1, 0, 10)
        if not result['OK']:
            return result

        allowedSubmitPools = getSubmitPools(self.__manifest['OwnerGroup'])
        result = self.__checkMultiChoice("SubmitPools",
                                         list(set(allowedSubmitPools)))
        if not result['OK']:
            return result

        result = self.__checkMultiChoice("PilotTypes", ['private'])
        if not result['OK']:
            return result

        maxInputData = Operations().getValue("JobDescription/MaxInputData",
                                             500)
        result = self.__checkMaxInputData(maxInputData)
        if not result['OK']:
            return result

        transformationTypes = Operations().getValue(
            "Transformations/DataProcessing", [])
        result = self.__checkMultiChoice(
            "JobType", ['User', 'Test', 'Hospital'] + transformationTypes)
        if not result['OK']:
            return result
        return S_OK()

    def createSection(self, secName, contents=False):
        if secName not in self.__manifest:
            if contents and not isinstance(contents, CFG):
                return S_ERROR("Contents for section %s is not a cfg object" %
                               secName)
            self.__dirty = True
            return S_OK(
                self.__manifest.createNewSection(secName, contents=contents))
        return S_ERROR("Section %s already exists" % secName)

    def getSection(self, secName):
        self.__dirty = True
        if secName not in self.__manifest:
            return S_ERROR("%s does not exist" % secName)
        sec = self.__manifest[secName]
        if not sec:
            return S_ERROR("%s section empty" % secName)
        return S_OK(sec)

    def setSectionContents(self, secName, contents):
        if contents and not isinstance(contents, CFG):
            return S_ERROR("Contents for section %s is not a cfg object" %
                           secName)
        self.__dirty = True
        if secName in self.__manifest:
            self.__manifest[secName].reset()
            self.__manifest[secName].mergeWith(contents)
        else:
            self.__manifest.createNewSection(secName, contents=contents)

    def setOption(self, varName, varValue):
        """
    Set a var in job manifest
    """
        self.__dirty = True
        levels = List.fromChar(varName, "/")
        cfg = self.__manifest
        for l in levels[:-1]:
            if l not in cfg:
                cfg.createNewSection(l)
            cfg = cfg[l]
        cfg.setOption(levels[-1], varValue)

    def remove(self, opName):
        levels = List.fromChar(opName, "/")
        cfg = self.__manifest
        for l in levels[:-1]:
            if l not in cfg:
                return S_ERROR("%s does not exist" % opName)
            cfg = cfg[l]
        if cfg.deleteKey(levels[-1]):
            self.__dirty = True
            return S_OK()
        return S_ERROR("%s does not exist" % opName)

    def getOption(self, varName, defaultValue=None):
        """
     Get a variable from the job manifest
    """
        cfg = self.__manifest
        return cfg.getOption(varName, defaultValue)

    def getOptionList(self, section=""):
        """
    Get a list of variables in a section of the job manifest
    """
        cfg = self.__manifest.getRecursive(section)
        if not cfg or 'value' not in cfg:
            return []
        cfg = cfg['value']
        return cfg.listOptions()

    def isOption(self, opName):
        """
    Check if it is a valid option
    """
        return self.__manifest.isOption(opName)

    def getSectionList(self, section=""):
        """
    Get a list of sections in the job manifest
    """
        cfg = self.__manifest.getRecursive(section)
        if not cfg or 'value' not in cfg:
            return []
        cfg = cfg['value']
        return cfg.listSections()
Example #6
0
class JobDescription(object):
    def __init__(self):
        self.__description = CFG()
        self.__dirty = False

    def isDirty(self):
        return self.__dirty

    def loadDescription(self, dataString):
        """
    Auto discover format type based on [ .. ] of JDL
    """
        dataString = dataString.strip()
        if dataString[0] == "[" and dataString[-1] == "]":
            return self.loadDescriptionFromJDL(dataString)
        else:
            return self.loadDescriptionFromCFG(dataString)

    def loadDescriptionFromJDL(self, jdlString):
        """
    Load job description from JDL format
    """
        result = loadJDLAsCFG(jdlString.strip())
        if not result['OK']:
            self.__description = CFG()
            return result
        self.__description = result['Value'][0]
        return S_OK()

    def loadDescriptionFromCFG(self, cfgString):
        """
    Load job description from CFG format
    """
        try:
            self.__description.loadFromBuffer(cfgString)
        except Exception as e:
            return S_ERROR("Can't load description from cfg: %s" % str(e))
        return S_OK()

    def dumpDescriptionAsCFG(self):
        return str(self.__description)

    def dumpDescriptionAsJDL(self):
        return dumpCFGAsJDL(self.__description)

    def __checkNumericalVarInDescription(self, varName, defaultVal, minVal,
                                         maxVal):
        """
    Check a numerical var
    """
        initialVal = 0
        if varName not in self.__description:
            varValue = Operations().getValue(
                "JobDescription/Default%s" % varName, defaultVal)
        else:
            varValue = self.__description[varName]
            initialVal = varValue
        try:
            varValue = long(varValue)
        except BaseException:
            return S_ERROR("%s must be a number" % varName)
        minVal = Operations().getValue("JobDescription/Min%s" % varName,
                                       minVal)
        maxVal = Operations().getValue("JobDescription/Max%s" % varName,
                                       maxVal)
        varValue = max(minVal, min(varValue, maxVal))
        if initialVal != varValue:
            self.__description.setOption(varName, varValue)
        return S_OK(varValue)

    def __checkChoiceVarInDescription(self, varName, defaultVal, choices):
        """
    Check a choice var
    """
        initialVal = False
        if varName not in self.__description:
            varValue = Operations().getValue(
                "JobDescription/Default%s" % varName, defaultVal)
        else:
            varValue = self.__description[varName]
            initialVal = varValue
        if varValue not in Operations().getValue(
                "JobDescription/Choices%s" % varName, choices):
            return S_ERROR("%s is not a valid value for %s" %
                           (varValue, varName))
        if initialVal != varValue:
            self.__description.setOption(varName, varValue)
        return S_OK(varValue)

    def __checkMultiChoiceInDescription(self, varName, choices):
        """
    Check a multi choice var
    """
        initialVal = False
        if varName not in self.__description:
            return S_OK()
        else:
            varValue = self.__description[varName]
            initialVal = varValue
        choices = Operations().getValue("JobDescription/Choices%s" % varName,
                                        choices)
        for v in List.fromChar(varValue):
            if v not in choices:
                return S_ERROR("%s is not a valid value for %s" % (v, varName))
        if initialVal != varValue:
            self.__description.setOption(varName, varValue)
        return S_OK(varValue)

    def __checkMaxInputData(self, maxNumber):
        """
    Check Maximum Number of Input Data files allowed
    """
        varName = "InputData"
        if varName not in self.__description:
            return S_OK()
        varValue = self.__description[varName]
        if len(List.fromChar(varValue)) > maxNumber:
            return S_ERROR(
                'Number of Input Data Files (%s) greater than current limit: %s'
                % (len(List.fromChar(varValue)), maxNumber))
        return S_OK()

    def setVarsFromDict(self, varDict):
        for k in sorted(varDict):
            self.setVar(k, varDict[k])

    def checkDescription(self):
        """
    Check that the description is OK
    """
        for k in ['OwnerName', 'OwnerDN', 'OwnerGroup', 'DIRACSetup']:
            if k not in self.__description:
                return S_ERROR("Missing var %s in description" % k)
        # Check CPUTime
        result = self.__checkNumericalVarInDescription("CPUTime", 86400, 0,
                                                       500000)
        if not result['OK']:
            return result
        result = self.__checkNumericalVarInDescription("Priority", 1, 0, 10)
        if not result['OK']:
            return result

        allowedSubmitPools = getSubmitPools(self.__description['OwnerGroup'])
        result = self.__checkMultiChoiceInDescription(
            "SubmitPools", list(set(allowedSubmitPools)))
        if not result['OK']:
            return result

        result = self.__checkMultiChoiceInDescription(
            "SubmitPools", list(set(allowedSubmitPools)))
        if not result['OK']:
            return result
        result = self.__checkMultiChoiceInDescription("PilotTypes",
                                                      ['private'])
        if not result['OK']:
            return result
        maxInputData = Operations().getValue("JobDescription/MaxInputData",
                                             500)
        result = self.__checkMaxInputData(maxInputData)
        if not result['OK']:
            return result
        transformationTypes = Operations().getValue(
            "Transformations/DataProcessing", [])
        result = self.__checkMultiChoiceInDescription(
            "JobType", ['User', 'Test', 'Hospital'] + transformationTypes)
        return S_OK()

    def setVar(self, varName, varValue):
        """
    Set a var in job description
    """
        self.__dirty = True
        levels = List.fromChar(varName, "/")
        cfg = self.__description
        for l in levels[:-1]:
            if l not in cfg:
                cfg.createNewSection(l)
            cfg = cfg[l]
        cfg.setOption(levels[-1], varValue)

    def getVar(self, varName, defaultValue=None):
        cfg = self.__description
        return cfg.getOption(varName, defaultValue)

    def getOptionList(self, section=""):
        cfg = self.__description.getRecursive(section)
        if not cfg or 'value' not in cfg:
            return []
        cfg = cfg['value']
        return cfg.listOptions()

    def getSectionList(self, section=""):
        cfg = self.__description.getRecursive(section)
        if not cfg or 'value' not in cfg:
            return []
        cfg = cfg['value']
        return cfg.listSections()
        return S_OK(modCfg.getComment(path))

    @jsonify
    def moveNode(self):
        try:
            nodePath = request.params['nodePath']
            destinationParentPath = request.params['parentPath']
            beforeOfIndex = int(request.params['beforeOfIndex'])
        except Exception, e:
            return S_ERROR("Can't decode parameter: %s" % str(e))

        gLogger.info("Moving %s under %s before pos %s" %
                     (nodePath, destinationParentPath, beforeOfIndex))
        cfgData = CFG()
        cfgData.loadFromBuffer(session['cfgData'])
        nodeDict = cfgData.getRecursive(nodePath)
        if not nodeDict:
            return S_ERROR("Moving entity does not exist")
        oldParentDict = cfgData.getRecursive(nodePath, -1)
        newParentDict = cfgData.getRecursive(destinationParentPath)
        if type(newParentDict) == types.StringType:
            return S_ERROR("Destination is not a section")
        if not newParentDict:
            return S_ERROR("Destination does not exist")
        #Calculate the old parent path
        oldParentPath = "/%s" % "/".join(List.fromChar(nodePath, "/")[:-1])
        if not oldParentPath == destinationParentPath and newParentDict[
                'value'].existsKey(nodeDict['key']):
            return S_ERROR("Another entry with the same name already exists")

        try:
Example #8
0
        session.save()
        return S_OK(modCfg.getComment(path))

    @jsonify
    def moveNode(self):
        try:
            nodePath = request.params["nodePath"]
            destinationParentPath = request.params["parentPath"]
            beforeOfIndex = int(request.params["beforeOfIndex"])
        except Exception, e:
            return S_ERROR("Can't decode parameter: %s" % str(e))

        gLogger.info("Moving %s under %s before pos %s" % (nodePath, destinationParentPath, beforeOfIndex))
        cfgData = CFG()
        cfgData.loadFromBuffer(session["cfgData"])
        nodeDict = cfgData.getRecursive(nodePath)
        if not nodeDict:
            return S_ERROR("Moving entity does not exist")
        oldParentDict = cfgData.getRecursive(nodePath, -1)
        newParentDict = cfgData.getRecursive(destinationParentPath)
        if type(newParentDict) == types.StringType:
            return S_ERROR("Destination is not a section")
        if not newParentDict:
            return S_ERROR("Destination does not exist")
        # Calculate the old parent path
        oldParentPath = "/%s" % "/".join(List.fromChar(nodePath, "/")[:-1])
        if not oldParentPath == destinationParentPath and newParentDict["value"].existsKey(nodeDict["key"]):
            return S_ERROR("Another entry with the same name already exists")

        try:
            brothers = newParentDict["value"].listAll()
Example #9
0
class JobDescription( object ):

  def __init__( self ):
    self.__description = CFG()
    self.__dirty = False

  def isDirty( self ):
    return self.__dirty

  def loadDescription( self, dataString ):
    """
    Auto discover format type based on [ .. ] of JDL
    """
    dataString = dataString.strip()
    if dataString[0] == "[" and dataString[-1] == "]":
      return self.loadDescriptionFromJDL( dataString )
    else:
      return self.loadDescriptionFromCFG( dataString )

  def loadDescriptionFromJDL( self, jdlString ):
    """
    Load job description from JDL format
    """
    result = loadJDLAsCFG( jdlString.strip() )
    if not result[ 'OK' ]:
      self.__description = CFG()
      return result
    self.__description = result[ 'Value' ][0]
    return S_OK()

  def loadDescriptionFromCFG( self, cfgString ):
    """
    Load job description from CFG format
    """
    try:
      self.__description.loadFromBuffer( cfgString )
    except Exception as e:
      return S_ERROR( "Can't load description from cfg: %s" % str( e ) )
    return S_OK()

  def dumpDescriptionAsCFG( self ):
    return str( self.__description )

  def dumpDescriptionAsJDL( self ):
    return dumpCFGAsJDL( self.__description )

  def __checkNumericalVarInDescription( self, varName, defaultVal, minVal, maxVal ):
    """
    Check a numerical var
    """
    initialVal = 0
    if varName not in self.__description:
      varValue = Operations().getValue( "JobDescription/Default%s" % varName , defaultVal )
    else:
      varValue = self.__description[ varName ]
      initialVal = varValue
    try:
      varValue = long( varValue )
    except:
      return S_ERROR( "%s must be a number" % varName )
    minVal = Operations().getValue( "JobDescription/Min%s" % varName, minVal )
    maxVal = Operations().getValue( "JobDescription/Max%s" % varName, maxVal )
    varValue = max( minVal, min( varValue, maxVal ) )
    if initialVal != varValue:
      self.__description.setOption( varName, varValue )
    return S_OK( varValue )

  def __checkChoiceVarInDescription( self, varName, defaultVal, choices ):
    """
    Check a choice var
    """
    initialVal = False
    if varName not in self.__description:
      varValue = Operations().getValue( "JobDescription/Default%s" % varName , defaultVal )
    else:
      varValue = self.__description[ varName ]
      initialVal = varValue
    if varValue not in Operations().getValue( "JobDescription/Choices%s" % varName , choices ):
      return S_ERROR( "%s is not a valid value for %s" % ( varValue, varName ) )
    if initialVal != varValue:
      self.__description.setOption( varName, varValue )
    return S_OK( varValue )

  def __checkMultiChoiceInDescription( self, varName, choices ):
    """
    Check a multi choice var
    """
    initialVal = False
    if varName not in self.__description:
      return S_OK()
    else:
      varValue = self.__description[ varName ]
      initialVal = varValue
    choices = Operations().getValue( "JobDescription/Choices%s" % varName , choices )
    for v in List.fromChar( varValue ):
      if v not in choices:
        return S_ERROR( "%s is not a valid value for %s" % ( v, varName ) )
    if initialVal != varValue:
      self.__description.setOption( varName, varValue )
    return S_OK( varValue )

  def __checkMaxInputData( self, maxNumber ):
    """
    Check Maximum Number of Input Data files allowed
    """
    varName = "InputData"
    if varName not in self.__description:
      return S_OK()
    varValue = self.__description[ varName ]
    if len( List.fromChar( varValue ) ) > maxNumber:
      return S_ERROR( 'Number of Input Data Files (%s) greater than current limit: %s' % ( len( List.fromChar( varValue ) ), maxNumber ) )
    return S_OK()

  def setVarsFromDict( self, varDict ):
    for k in sorted( varDict ):
      self.setVar( k, varDict[ k ] )

  def checkDescription( self ):
    """
    Check that the description is OK
    """
    for k in [ 'OwnerName', 'OwnerDN', 'OwnerGroup', 'DIRACSetup' ]:
      if k not in self.__description:
        return S_ERROR( "Missing var %s in description" % k )
    # Check CPUTime
    result = self.__checkNumericalVarInDescription( "CPUTime", 86400, 0, 500000 )
    if not result[ 'OK' ]:
      return result
    result = self.__checkNumericalVarInDescription( "Priority", 1, 0, 10 )
    if not result[ 'OK' ]:
      return result

    allowedSubmitPools = getSubmitPools( self.__description['OwnerGroup'] )
    result = self.__checkMultiChoiceInDescription( "SubmitPools", list( set( allowedSubmitPools ) ) )
    if not result[ 'OK' ]:
      return result

    result = self.__checkMultiChoiceInDescription( "SubmitPools", list( set( allowedSubmitPools ) ) )
    if not result[ 'OK' ]:
      return result
    result = self.__checkMultiChoiceInDescription( "PilotTypes", [ 'private' ] )
    if not result[ 'OK' ]:
      return result
    maxInputData = Operations().getValue( "JobDescription/MaxInputData", 500 )
    result = self.__checkMaxInputData( maxInputData )
    if not result[ 'OK' ]:
      return result
    transformationTypes = Operations().getValue( "Transformations/DataProcessing", [] )
    result = self.__checkMultiChoiceInDescription( "JobType", ['User', 'Test', 'Hospital'] + transformationTypes )
    return S_OK()

  def setVar( self, varName, varValue ):
    """
    Set a var in job description
    """
    self.__dirty = True
    levels = List.fromChar( varName, "/" )
    cfg = self.__description
    for l in levels[:-1]:
      if l not in cfg:
        cfg.createNewSection( l )
      cfg = cfg[ l ]
    cfg.setOption( levels[-1], varValue )

  def getVar( self, varName, defaultValue = None ):
    cfg = self.__description
    return cfg.getOption( varName, defaultValue )

  def getOptionList( self, section = "" ):
    cfg = self.__description.getRecursive( section )
    if not cfg or 'value' not in cfg:
      return []
    cfg = cfg[ 'value' ]
    return cfg.listOptions()

  def getSectionList( self, section = "" ):
    cfg = self.__description.getRecursive( section )
    if not cfg or 'value' not in cfg:
      return []
    cfg = cfg[ 'value' ]
    return cfg.listSections()