Beispiel #1
0
class LogStatusAction(BaseAction):
  '''
    Action that registers on the database a new entry on the <element>Status table.
    It adds or modifies if the record exists on the table.
  '''

  def __init__(self, name, decisionParams, enforcementResult, singlePolicyResults,
               clients=None):

    super(LogStatusAction, self).__init__(name, decisionParams, enforcementResult,
                                          singlePolicyResults, clients)

    if clients is not None and 'ResourceStatusClient' in clients:
      self.rsClient = clients['ResourceStatusClient']
    else:
      self.rsClient = ResourceStatusClient()

  def run(self):
    '''
      Checks it has the parameters it needs and tries to addOrModify in the
      database.
    '''
    # Minor security checks

    element = self.decisionParams['element']
    if element is None:
      return S_ERROR('element should not be None')

    name = self.decisionParams['name']
    if name is None:
      return S_ERROR('name should not be None')

    statusType = self.decisionParams['statusType']
    if statusType is None:
      return S_ERROR('statusType should not be None')

    status = self.enforcementResult['Status']
    if status is None:
      return S_ERROR('status should not be None')

    elementType = self.decisionParams['elementType']
    if elementType is None:
      return S_ERROR('elementType should not be None')

    reason = self.enforcementResult['Reason']
    if reason is None:
      return S_ERROR('reason should not be None')

    # Truncate reason to fit in database column
    reason = (reason[:508] + '..') if len(reason) > 508 else reason

    resLogUpdate = self.rsClient.addOrModifyStatusElement(element, 'Status',
                                                          name=name, statusType=statusType,
                                                          status=status, elementType=elementType,
                                                          reason=reason
                                                          )

    return resLogUpdate
Beispiel #2
0
class LogStatusAction(BaseAction):
    """
    Action that registers on the database a new entry on the <element>Status table.
    It adds or modifies if the record exists on the table.
  """

    def __init__(self, name, decisionParams, enforcementResult, singlePolicyResults, clients=None):

        super(LogStatusAction, self).__init__(name, decisionParams, enforcementResult, singlePolicyResults, clients)

        if clients is not None and "ResourceStatusClient" in clients:
            self.rsClient = clients["ResourceStatusClient"]
        else:
            self.rsClient = ResourceStatusClient()

    def run(self):
        """
      Checks it has the parameters it needs and tries to addOrModify in the
      database.
    """
        # Minor security checks

        element = self.decisionParams["element"]
        if element is None:
            return S_ERROR("element should not be None")

        name = self.decisionParams["name"]
        if name is None:
            return S_ERROR("name should not be None")

        statusType = self.decisionParams["statusType"]
        if statusType is None:
            return S_ERROR("statusType should not be None")

        status = self.enforcementResult["Status"]
        if status is None:
            return S_ERROR("status should not be None")

        elementType = self.decisionParams["elementType"]
        if elementType is None:
            return S_ERROR("elementType should not be None")

        reason = self.enforcementResult["Reason"]
        if reason is None:
            return S_ERROR("reason should not be None")

        # Truncate reason to fit in database column
        reason = (reason[:508] + "..") if len(reason) > 508 else reason

        resLogUpdate = self.rsClient.addOrModifyStatusElement(
            element, "Status", name=name, statusType=statusType, status=status, elementType=elementType, reason=reason
        )

        return resLogUpdate
Beispiel #3
0
class TokenAgent( AgentModule ):
  '''
    TokenAgent is in charge of checking tokens assigned on resources.
    Notifications are sent to those users owning expiring tokens.
  '''

  # Rss token
  __rssToken = 'rs_svc'

  def __init__( self, *args, **kwargs ):
    ''' c'tor
    '''

    AgentModule.__init__( self, *args, **kwargs )

    self.notifyHours = 12
    self.adminMail = ''

    self.rsClient = None
    self.tokenDict = {}
    self.diracAdmin = None

  def initialize( self ):
    ''' TokenAgent initialization
    '''

    self.notifyHours = self.am_getOption( 'notifyHours', self.notifyHours )
    self.adminMail   = self.am_getOption( 'adminMail', self.adminMail )

    self.rsClient = ResourceStatusClient()
    self.diracAdmin = DiracAdmin()

    return S_OK()

  def execute( self ):
    '''
      Looks for user tokens. If they are expired, or expiring, it notifies users.
    '''

    # Initialized here, as it is needed empty at the beginning of the execution
    self.tokenDict = {}

    elements = ( 'Site', 'Resource', 'Node' )

    for element in elements:

      self.log.info( 'Processing %s' % element )

      interestingTokens = self._getInterestingTokens( element )
      if not interestingTokens[ 'OK' ]:
        self.log.error( interestingTokens[ 'Message' ] )
        continue
      interestingTokens = interestingTokens[ 'Value' ]

      processTokens = self._processTokens( element, interestingTokens )
      if not processTokens[ 'OK' ]:
        self.log.error( processTokens[ 'Message' ] )
        continue

    notificationResult = self._notifyOfTokens()
    if not notificationResult[ 'OK' ]:
      self.log.error( notificationResult[ 'Message' ] )

    return S_OK()

  def _getInterestingTokens( self, element ):
    '''
      Given an element, picks all the entries with TokenExpiration < now + X<hours>
      If the TokenOwner is not the rssToken ( rs_svc ), it is selected.
    '''

    tokenExpLimit = datetime.utcnow() + timedelta( hours = self.notifyHours )

    tokenElements = self.rsClient.selectStatusElement( element, 'Status',
                                                       meta = { 'older' : ( 'TokenExpiration', tokenExpLimit ) } )

    if not tokenElements[ 'OK' ]:
      return tokenElements

    tokenColumns = tokenElements[ 'Columns' ]
    tokenElements = tokenElements[ 'Value' ]

    interestingTokens = []

    for tokenElement in tokenElements:

      tokenElement = dict( zip( tokenColumns, tokenElement ) )

      if tokenElement[ 'TokenOwner' ] != self.__rssToken:
        interestingTokens.append( tokenElement )

    return S_OK( interestingTokens )

  def _processTokens( self, element, tokenElements ):
    '''
      Given an element and a list of interesting token elements, updates the
      database if the token is expired, logs a message and adds
    '''

    never = datetime.max

    for tokenElement in tokenElements:

      try:
        name = tokenElement[ 'Name' ]
        statusType = tokenElement[ 'StatusType' ]
        status = tokenElement[ 'Status' ]
        tokenOwner = tokenElement[ 'TokenOwner' ]
        tokenExpiration = tokenElement[ 'TokenExpiration' ]
      except KeyError as e:
        return S_ERROR( e )

      # If token has already expired
      if tokenExpiration < datetime.utcnow():
        _msg = '%s with statusType "%s" and owner %s EXPIRED'
        self.log.info( _msg % ( name, statusType, tokenOwner ) )

        result = self.rsClient.addOrModifyStatusElement( element, 'Status', name = name,
                                                         statusType = statusType,
                                                         tokenOwner = self.__rssToken,
                                                         tokenExpiration = never )
        if not result[ 'OK' ]:
          return result

      else:
        _msg = '%s with statusType "%s" and owner %s -> %s'
        self.log.info( _msg % ( name, statusType, tokenOwner, tokenExpiration ) )

      if tokenOwner not in self.tokenDict:
        self.tokenDict[ tokenOwner ] = []

      self.tokenDict[ tokenOwner ].append( [ tokenOwner, element, name, statusType, status, tokenExpiration ] )

    return S_OK()

  def _notifyOfTokens( self ):
    '''
      Splits interesing tokens between expired and expiring. Also splits them
      among users. It ends sending notifications to the users.
    '''

    now = datetime.utcnow()

    adminExpired = []
    adminExpiring = []

    for tokenOwner, tokenLists in self.tokenDict.items():

      expired = []
      expiring = []

      for tokenList in tokenLists:

        if tokenList[ 5 ] < now:
          expired.append( tokenList )
          adminExpired.append( tokenList )
        else:
          expiring.append( tokenList )
          adminExpiring.append( tokenList )

      resNotify = self._notify( tokenOwner, expired, expiring )
      if not resNotify[ 'OK' ]:
        self.log.error( 'Failed to notify token owner', resNotify[ 'Message' ] )

    if (adminExpired or adminExpiring) and self.adminMail:
      return self._notify(self.adminMail, adminExpired, adminExpiring)

    return S_OK()

  def _notify( self, tokenOwner, expired, expiring ):
    '''
      Given a token owner and a list of expired and expiring tokens, sends an
      email to the user.
    '''

    subject = 'RSS token summary for tokenOwner %s' % tokenOwner

    mail = '\nEXPIRED tokens ( RSS has taken control of them )\n'
    for tokenList in expired:

      mail += ' '.join( [ str(x) for x in tokenList ] )
      mail += '\n'

    mail = '\nEXPIRING tokens ( RSS will take control of them )\n'
    for tokenList in expiring:

      mail += ' '.join( [ str(x) for x in tokenList ] )
      mail += '\n'

    mail += "\n\n You can extend for another 24 hours using the web interface (Set token -> Acquire)\n"
    mail += " Or you can use the dirac-rss-set-token script\n\n"
    mail += "Through the same interfaces you can release the token any time\n"

    # FIXME: you can re-take control of them using this or that...

    resEmail = self.diracAdmin.sendMail( tokenOwner, subject, mail )
    if not resEmail[ 'OK' ]:
      return S_ERROR( 'Cannot send email to user "%s"' % tokenOwner )

    return resEmail
Beispiel #4
0
class TokenAgent( AgentModule ):
  '''
    TokenAgent is in charge of checking tokens assigned on resources.
    Notifications are sent to those users owning expiring tokens.
  '''

  # Hours to notify a user
  __notifyHours = 12

  # Rss token
  __rssToken = 'rs_svc'

  # Admin mail
  __adminMail = None

  def __init__( self, *args, **kwargs ):
    ''' c'tor
    '''

    AgentModule.__init__( self, *args, **kwargs )

    self.notifyHours = self.__notifyHours
    self.adminMail = self.__adminMail

    self.rsClient = None
    self.rmClient = None
    self.noClient = None

    self.tokenDict = None
    self.diracAdmin = None

  def initialize( self ):
    ''' TokenAgent initialization
        Uses the ProductionManager shifterProxy to modify the ResourceStatus DB
    '''
    self.am_setOption( 'shifterProxy', 'ProductionManager' )

    self.notifyHours = self.am_getOption( 'notifyHours', self.notifyHours )

    self.rsClient = ResourceStatusClient()
    self.rmClient = ResourceManagementClient()
    self.noClient = NotificationClient()

    self.diracAdmin = DiracAdmin()

    return S_OK()

  def execute( self ):
    '''
      Looks for user tokens. If they are expired, or expiring, it notifies users.
    '''

    # Initialized here, as it is needed empty at the beginning of the execution
    self.tokenDict = {}

    # FIXME: probably this can be obtained from RssConfiguration instead
    elements = ( 'Site', 'Resource', 'Node' )

    for element in elements:

      self.log.info( 'Processing %s' % element )

      interestingTokens = self._getInterestingTokens( element )
      if not interestingTokens[ 'OK' ]:
        self.log.error( interestingTokens[ 'Message' ] )
        continue
      interestingTokens = interestingTokens[ 'Value' ]

      processTokens = self._processTokens( element, interestingTokens )
      if not processTokens[ 'OK' ]:
        self.log.error( processTokens[ 'Message' ] )
        continue

    notificationResult = self._notifyOfTokens()
    if not notificationResult[ 'OK' ]:
      self.log.error( notificationResult[ 'Message' ] )

    return S_OK()

  ## Protected methods #########################################################

  def _getInterestingTokens( self, element ):
    '''
      Given an element, picks all the entries with TokenExpiration < now + X<hours>
      If the TokenOwner is not the rssToken ( rs_svc ), it is selected.
    '''

    tokenExpLimit = datetime.utcnow() + timedelta( hours = self.notifyHours )

    tokenElements = self.rsClient.selectStatusElement( element, 'Status',
                                                       meta = { 'older' : ( 'TokenExpiration', tokenExpLimit ) } )

    if not tokenElements[ 'OK' ]:
      return tokenElements

    tokenColumns = tokenElements[ 'Columns' ]
    tokenElements = tokenElements[ 'Value' ]

    interestingTokens = []

    for tokenElement in tokenElements:

      tokenElement = dict( zip( tokenColumns, tokenElement ) )

      if tokenElement[ 'TokenOwner' ] != self.__rssToken:
        interestingTokens.append( tokenElement )

    return S_OK( interestingTokens )

  def _processTokens( self, element, tokenElements ):
    '''
      Given an element and a list of interesting token elements, updates the
      database if the token is expired, logs a message and adds
    '''

    never = datetime.max

    for tokenElement in tokenElements:

      try:
        name = tokenElement[ 'Name' ]
        statusType = tokenElement[ 'StatusType' ]
        status = tokenElement[ 'Status' ]
        tokenOwner = tokenElement[ 'TokenOwner' ]
        tokenExpiration = tokenElement[ 'TokenExpiration' ]
      except KeyError, e:
        return S_ERROR( e )

      # If token has already expired
      if tokenExpiration < datetime.utcnow():
        _msg = '%s with statusType "%s" and owner %s EXPIRED'
        self.log.info( _msg % ( name, statusType, tokenOwner ) )

        result = self.rsClient.addOrModifyStatusElement( element, 'Status', name = name,
                                                         statusType = statusType,
                                                         tokenOwner = self.__rssToken,
                                                         tokenExpiration = never )
        if not result[ 'OK' ]:
          return result

      else:
        _msg = '%s with statusType "%s" and owner %s -> %s'
        self.log.info( _msg % ( name, statusType, tokenOwner, tokenExpiration ) )

      if not tokenOwner in self.tokenDict:
        self.tokenDict[ tokenOwner ] = []

      self.tokenDict[ tokenOwner ].append( [ tokenOwner, element, name, statusType, status, tokenExpiration ] )

    return S_OK()
Beispiel #5
0
class TokenAgent(AgentModule):
    """
    TokenAgent is in charge of checking tokens assigned on resources.
    Notifications are sent to those users owning expiring tokens.
  """

    # Hours to notify a user
    __notifyHours = 12

    # Rss token
    __rssToken = "rs_svc"

    # Admin mail
    __adminMail = None

    def __init__(self, *args, **kwargs):
        """ c'tor
    """

        AgentModule.__init__(self, *args, **kwargs)

        self.notifyHours = self.__notifyHours
        self.adminMail = self.__adminMail

        self.rsClient = None
        self.tokenDict = None
        self.diracAdmin = None

    def initialize(self):
        """ TokenAgent initialization
    """

        self.notifyHours = self.am_getOption("notifyHours", self.notifyHours)
        self.adminMail = self.am_getOption("adminMail", self.adminMail)

        self.rsClient = ResourceStatusClient()
        self.diracAdmin = DiracAdmin()

        return S_OK()

    def execute(self):
        """
      Looks for user tokens. If they are expired, or expiring, it notifies users.
    """

        # Initialized here, as it is needed empty at the beginning of the execution
        self.tokenDict = {}

        # FIXME: probably this can be obtained from RssConfiguration instead
        elements = ("Site", "Resource", "Node")

        for element in elements:

            self.log.info("Processing %s" % element)

            interestingTokens = self._getInterestingTokens(element)
            if not interestingTokens["OK"]:
                self.log.error(interestingTokens["Message"])
                continue
            interestingTokens = interestingTokens["Value"]

            processTokens = self._processTokens(element, interestingTokens)
            if not processTokens["OK"]:
                self.log.error(processTokens["Message"])
                continue

        notificationResult = self._notifyOfTokens()
        if not notificationResult["OK"]:
            self.log.error(notificationResult["Message"])

        return S_OK()

    ## Protected methods #########################################################

    def _getInterestingTokens(self, element):
        """
      Given an element, picks all the entries with TokenExpiration < now + X<hours>
      If the TokenOwner is not the rssToken ( rs_svc ), it is selected.
    """

        tokenExpLimit = datetime.utcnow() + timedelta(hours=self.notifyHours)

        tokenElements = self.rsClient.selectStatusElement(
            element, "Status", meta={"older": ("TokenExpiration", tokenExpLimit)}
        )

        if not tokenElements["OK"]:
            return tokenElements

        tokenColumns = tokenElements["Columns"]
        tokenElements = tokenElements["Value"]

        interestingTokens = []

        for tokenElement in tokenElements:

            tokenElement = dict(zip(tokenColumns, tokenElement))

            if tokenElement["TokenOwner"] != self.__rssToken:
                interestingTokens.append(tokenElement)

        return S_OK(interestingTokens)

    def _processTokens(self, element, tokenElements):
        """
      Given an element and a list of interesting token elements, updates the
      database if the token is expired, logs a message and adds
    """

        never = datetime.max

        for tokenElement in tokenElements:

            try:
                name = tokenElement["Name"]
                statusType = tokenElement["StatusType"]
                status = tokenElement["Status"]
                tokenOwner = tokenElement["TokenOwner"]
                tokenExpiration = tokenElement["TokenExpiration"]
            except KeyError, e:
                return S_ERROR(e)

            # If token has already expired
            if tokenExpiration < datetime.utcnow():
                _msg = '%s with statusType "%s" and owner %s EXPIRED'
                self.log.info(_msg % (name, statusType, tokenOwner))

                result = self.rsClient.addOrModifyStatusElement(
                    element,
                    "Status",
                    name=name,
                    statusType=statusType,
                    tokenOwner=self.__rssToken,
                    tokenExpiration=never,
                )
                if not result["OK"]:
                    return result

            else:
                _msg = '%s with statusType "%s" and owner %s -> %s'
                self.log.info(_msg % (name, statusType, tokenOwner, tokenExpiration))

            if not tokenOwner in self.tokenDict:
                self.tokenDict[tokenOwner] = []

            self.tokenDict[tokenOwner].append([tokenOwner, element, name, statusType, status, tokenExpiration])

        return S_OK()
Beispiel #6
0
class ResourceStatus( object ):
  """
  ResourceStatus helper that connects to CS if RSS flag is not Active. It keeps
  the connection to the db / server as an object member, to avoid creating a new
  one massively.
  """

  __metaclass__ = DIRACSingleton

  def __init__( self, rssFlag = None ):
    """
    Constructor, initializes the rssClient.
    """
    self.log = gLogger.getSubLogger( self.__class__.__name__ )
    self.rssConfig = RssConfiguration()
    self.__opHelper = Operations()
    self.rssClient = ResourceStatusClient()
    self.rssFlag = rssFlag
    if rssFlag is None:
      self.rssFlag = self.__getMode()

    # We can set CacheLifetime and CacheHistory from CS, so that we can tune them.
    cacheLifeTime = int( self.rssConfig.getConfigCache() )

    # RSSCache only affects the calls directed to RSS, if using the CS it is not used.
    self.rssCache = RSSCache( cacheLifeTime, self.__updateRssCache )

  def getElementStatus( self, elementName, elementType, statusType = None, default = None ):
    """
    Helper function, tries to get information from the RSS for the given
    Element, otherwise, it gets it from the CS.

    :param elementName: name of the element
    :type elementName: str
    :param elementType: type of the element (StorageElement, ComputingElement, FTS, Catalog)
    :type elementType: str
    :param statusType: type of the status (meaningful only when elementType==StorageElement)
    :type statusType: None, str, list
    :param default: defult value (meaningful only when rss is InActive)
    :type default: str
    :return: S_OK/S_ERROR
    :rtype: dict

    :Example:
    >>> getElementStatus('CE42', 'ComputingElement')
        S_OK( { 'CE42': { 'all': 'Active' } } } )
    >>> getElementStatus('SE1', 'StorageElement', 'ReadAccess')
        S_OK( { 'SE1': { 'ReadAccess': 'Banned' } } } )
    >>> getElementStatus('SE1', 'ThisIsAWrongElementType', 'ReadAccess')
        S_ERROR( xyz.. )
    >>> getElementStatus('ThisIsAWrongName', 'StorageElement', 'WriteAccess')
        S_ERROR( xyz.. )
    >>> getElementStatus('A_file_catalog', 'FileCatalog')
        S_OK( { 'A_file_catalog': { 'all': 'Active' } } } )
    >>> getElementStatus('SE1', 'StorageElement', ['ReadAccess', 'WriteAccess'])
        S_OK( { 'SE1': { 'ReadAccess': 'Banned' , 'WriteAccess': 'Active'} } } )
    >>> getElementStatus('SE1', 'StorageElement')
        S_OK( { 'SE1': { 'ReadAccess': 'Probing' ,
                         'WriteAccess': 'Active',
                         'CheckAccess': 'Degraded',
                         'RemoveAccess': 'Banned'} } } )
    """

    allowedParameters = ["StorageElement", "ComputingElement", "FTS", "Catalog"]

    if elementType not in allowedParameters:
      return S_ERROR("%s in not in the list of the allowed parameters: %s" % (elementType, allowedParameters))

    # Apply defaults
    if not statusType:
      if elementType == "StorageElement":
        statusType = ['ReadAccess', 'WriteAccess', 'CheckAccess', 'RemoveAccess']
      elif elementType == "ComputingElement":
        statusType = ['all']
      elif elementType == "FTS":
        statusType = ['all']
      elif elementType == "Catalog":
        statusType = ['all']

    if self.rssFlag:
      return self.__getRSSElementStatus( elementName, elementType, statusType )
    else:
      return self.__getCSElementStatus( elementName, elementType, statusType, default )

  def setElementStatus( self, elementName, elementType, statusType, status, reason = None, tokenOwner = None ):
    """ Tries set information in RSS and in CS.

    :param elementName: name of the element
    :type elementName: str
    :param elementType: type of the element (StorageElement, ComputingElement, FTS, Catalog)
    :type elementType: str
    :param statusType: type of the status (meaningful only when elementType==StorageElement)
    :type statusType: str
    :param reason: reason for setting the status
    :type reason: str
    :param tokenOwner: owner of the token (meaningful only when rss is Active)
    :type tokenOwner: str
    :return: S_OK/S_ERROR
    :rtype: dict

    :Example:
    >>> setElementStatus('CE42', 'ComputingElement', 'all', 'Active')
        S_OK(  xyz.. )
    >>> setElementStatus('SE1', 'StorageElement', 'ReadAccess', 'Banned')
        S_OK(  xyz.. )
    """

    if self.rssFlag:
      return self.__setRSSElementStatus( elementName, elementType, statusType, status, reason, tokenOwner )
    else:
      return self.__setCSElementStatus( elementName, elementType, statusType, status )

################################################################################

  def __updateRssCache( self ):
    """ Method used to update the rssCache.

        It will try 5 times to contact the RSS before giving up
    """

    meta = { 'columns' : [ 'Name', 'ElementType', 'StatusType', 'Status' ] }

    for ti in range( 5 ):
      rawCache = self.rssClient.selectStatusElement( 'Resource', 'Status', meta = meta )
      if rawCache['OK']:
        break
      self.log.warn( "Can't get resource's status", rawCache['Message'] + "; trial %d" % ti )
      sleep( math.pow( ti, 2 ) )
      self.rssClient = ResourceStatusClient()

    if not rawCache[ 'OK' ]:
      return rawCache
    return S_OK( getCacheDictFromRawData( rawCache[ 'Value' ] ) )

################################################################################

  def __getRSSElementStatus( self, elementName, elementType, statusType ):
    """ Gets from the cache or the RSS the Elements status. The cache is a
        copy of the DB table. If it is not on the cache, most likely is not going
        to be on the DB.

        There is one exception: item just added to the CS, e.g. new Element.
        The period between it is added to the DB and the changes are propagated
        to the cache will be inconsistent, but not dangerous. Just wait <cacheLifeTime>
        minutes.

  :param elementName: name of the element
  :type elementName: str
  :param elementType: type of the element (StorageElement, ComputingElement, FTS, Catalog)
  :type elementType: str
  :param statusType: type of the status (meaningful only when elementType==StorageElement,
                     otherwise it is 'all' or ['all'])
  :type statusType: str, list
  """

    cacheMatch = self.rssCache.match( elementName, elementType, statusType )

    self.log.debug( '__getRSSElementStatus' )
    self.log.debug( cacheMatch )

    return cacheMatch

  def __getCSElementStatus( self, elementName, elementType, statusType, default ):
    """ Gets from the CS the Element status

    :param elementName: name of the element
    :type elementName: str
    :param elementType: type of the element (StorageElement, ComputingElement, FTS, Catalog)
    :type elementType: str
    :param statusType: type of the status (meaningful only when elementType==StorageElement)
    :type statusType: str, list
    :param default: defult value
    :type default: None, str
    """

    # DIRAC doesn't store the status of ComputingElements nor FTS in the CS, so here we can just return 'Active'
    if elementType in ('ComputingElement', 'FTS'):
      return S_OK( { elementName: { 'all': 'Active'} } )

    # If we are here it is because elementType is either 'StorageElement' or 'Catalog'
    if elementType == 'StorageElement':
      cs_path = "/Resources/StorageElements"
    elif elementType == 'Catalog':
      cs_path = "/Resources/FileCatalogs"
      statusType = ['Status']

    if not isinstance( elementName, list ):
      elementName = [ elementName ]

    if not isinstance( statusType, list ):
      statusType = [ statusType ]

    result = {}
    for element in elementName:

      for sType in statusType:
        # Look in standard location, 'Active' by default
        res = gConfig.getValue( "%s/%s/%s" % ( cs_path, element, sType ), 'Active' )
        result.setdefault( element, {} )[sType] = res

    if result:
      return S_OK( result )

    if default is not None:
      defList = [ [ el, statusType, default ] for el in elementName ]
      return S_OK( getDictFromList( defList ) )

    _msg = "Element '%s', with statusType '%s' is unknown for CS."
    return S_ERROR( DErrno.ERESUNK, _msg % ( elementName, statusType ) )

  def __setRSSElementStatus( self, elementName, elementType, statusType, status, reason, tokenOwner ):
    """
    Sets on the RSS the Elements status
    """

    expiration = datetime.utcnow() + timedelta( days = 1 )

    self.rssCache.acquireLock()
    try:
      res = self.rssClient.addOrModifyStatusElement( 'Resource', 'Status', name = elementName,
                                                     elementType = elementType, status = status,
                                                     statusType = statusType, reason = reason,
                                                     tokenOwner = tokenOwner, tokenExpiration = expiration )

      if res[ 'OK' ]:
        self.rssCache.refreshCache()

      if not res[ 'OK' ]:
        _msg = 'Error updating Element (%s,%s,%s)' % ( elementName, statusType, status )
        gLogger.warn( 'RSS: %s' % _msg )

      return res

    finally:
      # Release lock, no matter what.
      self.rssCache.releaseLock()

  def __setCSElementStatus( self, elementName, elementType, statusType, status ):
    """
    Sets on the CS the Elements status
    """

    # DIRAC doesn't store the status of ComputingElements nor FTS in the CS, so here we can just do nothing
    if elementType in ('ComputingElement', 'FTS'):
      return S_OK()

    # If we are here it is because elementType is either 'StorageElement' or 'Catalog'
    statuses = self.rssConfig.getConfigStatusType( elementType )
    if statusType not in statuses:
      gLogger.error( "%s is not a valid statusType" % statusType )
      return S_ERROR( "%s is not a valid statusType: %s" % ( statusType, statuses ) )

    if elementType == 'StorageElement':
      cs_path = "/Resources/StorageElements"
    elif elementType == 'Catalog':
      cs_path = "/Resources/FileCatalogs"
      #FIXME: This a probably outdated location (new one is in /Operations/[]/Services/Catalogs)
      # but needs to be VO-aware
      statusType = 'Status'

    csAPI = CSAPI()
    csAPI.setOption( "%s/%s/%s/%s" % ( cs_path, elementName, elementType, statusType ), status )

    res = csAPI.commitChanges()
    if not res[ 'OK' ]:
      gLogger.warn( 'CS: %s' % res[ 'Message' ] )

    return res

  def __getMode( self ):
    """
      Get's flag defined ( or not ) on the RSSConfiguration. If defined as 1,
      we use RSS, if not, we use CS.
    """

    res = self.rssConfig.getConfigState()

    if res == 'Active':
      if self.rssClient is None:
        self.rssClient = ResourceStatusClient()
      return True

    self.rssClient = None
    return False

  def isStorageElementAlwaysBanned( self, seName, statusType ):
    """ Checks if the AlwaysBanned policy is applied to the SE given as parameter

    :param seName : string, name of the SE
    :param statusType : ReadAcces, WriteAccess, RemoveAccess, CheckAccess

    :returns: S_OK(True/False)
    """

    res = getPoliciesThatApply( {'name' : seName, 'statusType' : statusType} )
    if not res['OK']:
      self.log.error( "isStorageElementAlwaysBanned: unable to get the information", res['Message'] )
      return res

    isAlwaysBanned = 'AlwaysBanned' in [policy['type'] for policy in res['Value']]

    return S_OK( isAlwaysBanned )
Beispiel #7
0
class TokenAgent(AgentModule):
    '''
    TokenAgent is in charge of checking tokens assigned on resources.
    Notifications are sent to those users owning expiring tokens.
  '''

    # Hours to notify a user
    __notifyHours = 12

    # Rss token
    __rssToken = 'rs_svc'

    # Admin mail
    __adminMail = None

    def __init__(self, *args, **kwargs):
        ''' c'tor
    '''

        AgentModule.__init__(self, *args, **kwargs)

        self.notifyHours = self.__notifyHours
        self.adminMail = self.__adminMail

        self.rsClient = None
        self.tokenDict = None
        self.diracAdmin = None

    def initialize(self):
        ''' TokenAgent initialization
    '''

        self.notifyHours = self.am_getOption('notifyHours', self.notifyHours)
        self.adminMail = self.am_getOption('adminMail', self.adminMail)

        self.rsClient = ResourceStatusClient()
        self.diracAdmin = DiracAdmin()

        return S_OK()

    def execute(self):
        '''
      Looks for user tokens. If they are expired, or expiring, it notifies users.
    '''

        # Initialized here, as it is needed empty at the beginning of the execution
        self.tokenDict = {}

        # FIXME: probably this can be obtained from RssConfiguration instead
        elements = ('Site', 'Resource', 'Node')

        for element in elements:

            self.log.info('Processing %s' % element)

            interestingTokens = self._getInterestingTokens(element)
            if not interestingTokens['OK']:
                self.log.error(interestingTokens['Message'])
                continue
            interestingTokens = interestingTokens['Value']

            processTokens = self._processTokens(element, interestingTokens)
            if not processTokens['OK']:
                self.log.error(processTokens['Message'])
                continue

        notificationResult = self._notifyOfTokens()
        if not notificationResult['OK']:
            self.log.error(notificationResult['Message'])

        return S_OK()

    ## Protected methods #########################################################

    def _getInterestingTokens(self, element):
        '''
      Given an element, picks all the entries with TokenExpiration < now + X<hours>
      If the TokenOwner is not the rssToken ( rs_svc ), it is selected.
    '''

        tokenExpLimit = datetime.utcnow() + timedelta(hours=self.notifyHours)

        tokenElements = self.rsClient.selectStatusElement(
            element,
            'Status',
            meta={'older': ('TokenExpiration', tokenExpLimit)})

        if not tokenElements['OK']:
            return tokenElements

        tokenColumns = tokenElements['Columns']
        tokenElements = tokenElements['Value']

        interestingTokens = []

        for tokenElement in tokenElements:

            tokenElement = dict(zip(tokenColumns, tokenElement))

            if tokenElement['TokenOwner'] != self.__rssToken:
                interestingTokens.append(tokenElement)

        return S_OK(interestingTokens)

    def _processTokens(self, element, tokenElements):
        '''
      Given an element and a list of interesting token elements, updates the
      database if the token is expired, logs a message and adds
    '''

        never = datetime.max

        for tokenElement in tokenElements:

            try:
                name = tokenElement['Name']
                statusType = tokenElement['StatusType']
                status = tokenElement['Status']
                tokenOwner = tokenElement['TokenOwner']
                tokenExpiration = tokenElement['TokenExpiration']
            except KeyError, e:
                return S_ERROR(e)

            # If token has already expired
            if tokenExpiration < datetime.utcnow():
                _msg = '%s with statusType "%s" and owner %s EXPIRED'
                self.log.info(_msg % (name, statusType, tokenOwner))

                result = self.rsClient.addOrModifyStatusElement(
                    element,
                    'Status',
                    name=name,
                    statusType=statusType,
                    tokenOwner=self.__rssToken,
                    tokenExpiration=never)
                if not result['OK']:
                    return result

            else:
                _msg = '%s with statusType "%s" and owner %s -> %s'
                self.log.info(_msg %
                              (name, statusType, tokenOwner, tokenExpiration))

            if not tokenOwner in self.tokenDict:
                self.tokenDict[tokenOwner] = []

            self.tokenDict[tokenOwner].append([
                tokenOwner, element, name, statusType, status, tokenExpiration
            ])

        return S_OK()
Beispiel #8
0
class LogStatusAction(BaseAction):
    """
    Action that registers on the database a new entry on the <element>Status table.
    It adds or modifies if the record exists on the table.
    """
    def __init__(self,
                 name,
                 decisionParams,
                 enforcementResult,
                 singlePolicyResults,
                 clients=None):

        super(LogStatusAction,
              self).__init__(name, decisionParams, enforcementResult,
                             singlePolicyResults, clients)

        if clients is not None and "ResourceStatusClient" in clients:
            self.rsClient = clients["ResourceStatusClient"]
        else:
            self.rsClient = ResourceStatusClient()

    def run(self):
        """
        Checks it has the parameters it needs and tries to addOrModify in the
        database.
        """
        # Minor security checks

        element = self.decisionParams["element"]
        if element is None:
            return S_ERROR("element should not be None")

        name = self.decisionParams["name"]
        if name is None:
            return S_ERROR("name should not be None")

        statusType = self.decisionParams["statusType"]
        if statusType is None:
            return S_ERROR("statusType should not be None")

        status = self.enforcementResult["Status"]
        if status is None:
            return S_ERROR("status should not be None")

        elementType = self.decisionParams["elementType"]
        if elementType is None:
            return S_ERROR("elementType should not be None")

        reason = self.enforcementResult["Reason"]
        if reason is None:
            return S_ERROR("reason should not be None")

        vo = self.enforcementResult.get("VO")
        # Truncate reason to fit in database column
        reason = (reason[:508] + "..") if len(reason) > 508 else reason
        # VO = 'all' (non-VO aware policy) for a combined policy affects all VOs for a given site or resource,
        if vo == "all":
            resSelect = self.rsClient.selectStatusElement(
                element,
                "Status",
                name=name,
                statusType=None,
                vO=None,
                status=None,
                elementType=None,
                reason=None,
                dateEffective=None,
                lastCheckTime=None,
                tokenOwner="rs_svc",
                tokenExpiration=None,
                meta=None,
            )
            if not resSelect["OK"]:
                self.log.error("Could not obtain all VO rows for element: %s" %
                               element)
                return resSelect
            voColumnIndex = resSelect["Columns"].index("VO")
            for row in resSelect["Value"]:
                vo = row[voColumnIndex]
                resLogUpdate = self.rsClient.addOrModifyStatusElement(
                    element,
                    "Status",
                    name=name,
                    statusType=statusType,
                    vO=vo,
                    status=status,
                    elementType=elementType,
                    reason=reason,
                )
                self.log.debug("Update result", resLogUpdate)

        else:
            resLogUpdate = self.rsClient.addOrModifyStatusElement(
                element,
                "Status",
                name=name,
                statusType=statusType,
                vO=vo,
                status=status,
                elementType=elementType,
                reason=reason,
            )

        return resLogUpdate
Beispiel #9
0
class TokenAgent(AgentModule):
    """
    TokenAgent is in charge of checking tokens assigned on resources.
    Notifications are sent to those users owning expiring tokens.
    """

    # Rss token
    __rssToken = "rs_svc"

    def __init__(self, *args, **kwargs):
        """c'tor"""

        AgentModule.__init__(self, *args, **kwargs)

        self.notifyHours = 12
        self.adminMail = ""

        self.rsClient = None
        self.tokenDict = {}
        self.diracAdmin = None

    def initialize(self):
        """TokenAgent initialization"""

        self.notifyHours = self.am_getOption("notifyHours", self.notifyHours)
        self.adminMail = self.am_getOption("adminMail", self.adminMail)

        self.rsClient = ResourceStatusClient()
        self.diracAdmin = DiracAdmin()

        return S_OK()

    def execute(self):
        """
        Looks for user tokens. If they are expired, or expiring, it notifies users.
        """

        # Initialized here, as it is needed empty at the beginning of the execution
        self.tokenDict = {}

        elements = ("Site", "Resource", "Node")

        for element in elements:

            self.log.info("Processing %s" % element)

            interestingTokens = self._getInterestingTokens(element)
            if not interestingTokens["OK"]:
                self.log.error(interestingTokens["Message"])
                continue
            interestingTokens = interestingTokens["Value"]

            processTokens = self._processTokens(element, interestingTokens)
            if not processTokens["OK"]:
                self.log.error(processTokens["Message"])
                continue

        notificationResult = self._notifyOfTokens()
        if not notificationResult["OK"]:
            self.log.error(notificationResult["Message"])

        return S_OK()

    def _getInterestingTokens(self, element):
        """
        Given an element, picks all the entries with TokenExpiration < now + X<hours>
        If the TokenOwner is not the rssToken ( rs_svc ), it is selected.
        """

        tokenExpLimit = datetime.utcnow() + timedelta(hours=self.notifyHours)

        tokenElements = self.rsClient.selectStatusElement(
            element,
            "Status",
            meta={"older": ["TokenExpiration", tokenExpLimit]})

        if not tokenElements["OK"]:
            return tokenElements

        tokenColumns = tokenElements["Columns"]
        tokenElements = tokenElements["Value"]

        interestingTokens = []

        for tokenElement in tokenElements:

            tokenElement = dict(zip(tokenColumns, tokenElement))

            if tokenElement["TokenOwner"] != self.__rssToken:
                interestingTokens.append(tokenElement)

        return S_OK(interestingTokens)

    def _processTokens(self, element, tokenElements):
        """
        Given an element and a list of interesting token elements, updates the
        database if the token is expired, logs a message and adds
        """

        never = datetime.max

        for tokenElement in tokenElements:

            try:
                name = tokenElement["Name"]
                statusType = tokenElement["StatusType"]
                status = tokenElement["Status"]
                tokenOwner = tokenElement["TokenOwner"]
                tokenExpiration = tokenElement["TokenExpiration"]
            except KeyError as e:
                return S_ERROR(e)

            # If token has already expired
            if tokenExpiration < datetime.utcnow():
                _msg = '%s with statusType "%s" and owner %s EXPIRED'
                self.log.info(_msg % (name, statusType, tokenOwner))

                result = self.rsClient.addOrModifyStatusElement(
                    element,
                    "Status",
                    name=name,
                    statusType=statusType,
                    tokenOwner=self.__rssToken,
                    tokenExpiration=never,
                )
                if not result["OK"]:
                    return result

            else:
                _msg = '%s with statusType "%s" and owner %s -> %s'
                self.log.info(_msg %
                              (name, statusType, tokenOwner, tokenExpiration))

            if tokenOwner not in self.tokenDict:
                self.tokenDict[tokenOwner] = []

            self.tokenDict[tokenOwner].append([
                tokenOwner, element, name, statusType, status, tokenExpiration
            ])

        return S_OK()

    def _notifyOfTokens(self):
        """
        Splits interesing tokens between expired and expiring. Also splits them
        among users. It ends sending notifications to the users.
        """

        now = datetime.utcnow()

        adminExpired = []
        adminExpiring = []

        for tokenOwner, tokenLists in self.tokenDict.items():

            expired = []
            expiring = []

            for tokenList in tokenLists:

                if tokenList[5] < now:
                    expired.append(tokenList)
                    adminExpired.append(tokenList)
                else:
                    expiring.append(tokenList)
                    adminExpiring.append(tokenList)

            resNotify = self._notify(tokenOwner, expired, expiring)
            if not resNotify["OK"]:
                self.log.error("Failed to notify token owner",
                               resNotify["Message"])

        if (adminExpired or adminExpiring) and self.adminMail:
            return self._notify(self.adminMail, adminExpired, adminExpiring)

        return S_OK()

    def _notify(self, tokenOwner, expired, expiring):
        """
        Given a token owner and a list of expired and expiring tokens, sends an
        email to the user.
        """

        subject = "RSS token summary for tokenOwner %s" % tokenOwner

        mail = "\nEXPIRED tokens ( RSS has taken control of them )\n"
        for tokenList in expired:

            mail += " ".join([str(x) for x in tokenList])
            mail += "\n"

        mail = "\nEXPIRING tokens ( RSS will take control of them )\n"
        for tokenList in expiring:

            mail += " ".join([str(x) for x in tokenList])
            mail += "\n"

        mail += "\n\n You can extend for another 24 hours using the web interface (Set token -> Acquire)\n"
        mail += " Or you can use the dirac-rss-set-token script\n\n"
        mail += "Through the same interfaces you can release the token any time\n"

        resEmail = self.diracAdmin.sendMail(tokenOwner, subject, mail)
        if not resEmail["OK"]:
            return S_ERROR('Cannot send email to user "%s"' % tokenOwner)

        return resEmail
Beispiel #10
0
class ResourceStatus(object):
  """
  ResourceStatus helper that connects to CS if RSS flag is not Active. It keeps
  the connection to the db / server as an object member, to avoid creating a new
  one massively.
  """

  __metaclass__ = DIRACSingleton

  def __init__(self, rssFlag=None):
    """
    Constructor, initializes the rssClient.
    """
    self.log = gLogger.getSubLogger(self.__class__.__name__)
    self.rssConfig = RssConfiguration()
    self.__opHelper = Operations()
    self.rssClient = ResourceStatusClient()
    self.rssFlag = rssFlag
    if rssFlag is None:
      self.rssFlag = self.__getMode()

    cacheLifeTime = int(self.rssConfig.getConfigCache())

    # RSSCache only affects the calls directed to RSS, if using the CS it is not used.
    self.rssCache = RSSCache(cacheLifeTime, self.__updateRssCache)

  def getElementStatus(self, elementName, elementType, statusType=None, default=None):
    """
    Helper function, tries to get information from the RSS for the given
    Element, otherwise, it gets it from the CS.

    :param elementName: name of the element or list of element names
    :type elementName: str, list
    :param elementType: type of the element (StorageElement, ComputingElement, FTS, Catalog)
    :type elementType: str
    :param statusType: type of the status (meaningful only when elementType==StorageElement)
    :type statusType: None, str, list
    :param default: defult value (meaningful only when rss is InActive)
    :type default: str
    :return: S_OK/S_ERROR
    :rtype: dict

    :Example:

    >>> getElementStatus('CE42', 'ComputingElement')
        S_OK( { 'CE42': { 'all': 'Active' } } } )
    >>> getElementStatus('SE1', 'StorageElement', 'ReadAccess')
        S_OK( { 'SE1': { 'ReadAccess': 'Banned' } } } )
    >>> getElementStatus('SE1', 'ThisIsAWrongElementType', 'ReadAccess')
        S_ERROR( xyz.. )
    >>> getElementStatus('ThisIsAWrongName', 'StorageElement', 'WriteAccess')
        S_ERROR( xyz.. )
    >>> getElementStatus('A_file_catalog', 'FileCatalog')
        S_OK( { 'A_file_catalog': { 'all': 'Active' } } } )
    >>> getElementStatus('SE1', 'StorageElement', ['ReadAccess', 'WriteAccess'])
        S_OK( { 'SE1': { 'ReadAccess': 'Banned' , 'WriteAccess': 'Active'} } } )
    >>> getElementStatus('SE1', 'StorageElement')
        S_OK( { 'SE1': { 'ReadAccess': 'Probing' ,
                         'WriteAccess': 'Active',
                         'CheckAccess': 'Degraded',
                         'RemoveAccess': 'Banned'} } } )
    >>> getElementStatus(['CE1', 'CE2'], 'ComputingElement')
        S_OK( {'CE1': {'all': 'Active'},
               'CE2': {'all': 'Probing'}}}
    """

    allowedParameters = ["StorageElement", "ComputingElement", "FTS", "Catalog"]

    if elementType not in allowedParameters:
      return S_ERROR("%s in not in the list of the allowed parameters: %s" % (elementType, allowedParameters))

    # Apply defaults
    if not statusType:
      if elementType == "StorageElement":
        statusType = ['ReadAccess', 'WriteAccess', 'CheckAccess', 'RemoveAccess']
      elif elementType == "ComputingElement":
        statusType = ['all']
      elif elementType == "FTS":
        statusType = ['all']
      elif elementType == "Catalog":
        statusType = ['all']

    if self.rssFlag:
      return self.__getRSSElementStatus(elementName, elementType, statusType)
    else:
      return self.__getCSElementStatus(elementName, elementType, statusType, default)

  def setElementStatus(self, elementName, elementType, statusType, status, reason=None, tokenOwner=None):
    """ Tries set information in RSS and in CS.

    :param elementName: name of the element
    :type elementName: str
    :param elementType: type of the element (StorageElement, ComputingElement, FTS, Catalog)
    :type elementType: str
    :param statusType: type of the status (meaningful only when elementType==StorageElement)
    :type statusType: str
    :param reason: reason for setting the status
    :type reason: str
    :param tokenOwner: owner of the token (meaningful only when rss is Active)
    :type tokenOwner: str
    :return: S_OK/S_ERROR
    :rtype: dict

    :Example:

    >>> setElementStatus('CE42', 'ComputingElement', 'all', 'Active')
        S_OK(  xyz.. )
    >>> setElementStatus('SE1', 'StorageElement', 'ReadAccess', 'Banned')
        S_OK(  xyz.. )
    """

    if self.rssFlag:
      return self.__setRSSElementStatus(elementName, elementType, statusType, status, reason, tokenOwner)
    else:
      return self.__setCSElementStatus(elementName, elementType, statusType, status)

################################################################################

  def __updateRssCache(self):
    """ Method used to update the rssCache.

        It will try 5 times to contact the RSS before giving up
    """

    meta = {'columns': ['Name', 'ElementType', 'StatusType', 'Status']}

    for ti in range(5):
      rawCache = self.rssClient.selectStatusElement('Resource', 'Status', meta=meta)
      if rawCache['OK']:
        break
      self.log.warn("Can't get resource's status", rawCache['Message'] + "; trial %d" % ti)
      sleep(math.pow(ti, 2))
      self.rssClient = ResourceStatusClient()

    if not rawCache['OK']:
      return rawCache
    return S_OK(getCacheDictFromRawData(rawCache['Value']))

################################################################################

  def __getRSSElementStatus(self, elementName, elementType, statusType):
    """ Gets from the cache or the RSS the Elements status. The cache is a
        copy of the DB table. If it is not on the cache, most likely is not going
        to be on the DB.

        There is one exception: item just added to the CS, e.g. new Element.
        The period between it is added to the DB and the changes are propagated
        to the cache will be inconsistent, but not dangerous. Just wait <cacheLifeTime>
        minutes.

    :param elementName: name of the element or list of element names
    :type elementName: str, list
    :param elementType: type of the element (StorageElement, ComputingElement, FTS, Catalog)
    :type elementType: str
    :param statusType: type of the status (meaningful only when elementType==StorageElement,
                       otherwise it is 'all' or ['all'])
    :type statusType: str, list
    """

    cacheMatch = self.rssCache.match(elementName, elementType, statusType)

    self.log.debug('__getRSSElementStatus')
    self.log.debug(cacheMatch)

    return cacheMatch

  def __getCSElementStatus(self, elementName, elementType, statusType, default):
    """ Gets from the CS the Element status

    :param elementName: name of the element
    :type elementName: str
    :param elementType: type of the element (StorageElement, ComputingElement, FTS, Catalog)
    :type elementType: str
    :param statusType: type of the status (meaningful only when elementType==StorageElement)
    :type statusType: str, list
    :param default: defult value
    :type default: None, str
    """

    # DIRAC doesn't store the status of ComputingElements nor FTS in the CS, so here we can just return 'Active'
    if elementType in ('ComputingElement', 'FTS'):
      return S_OK({elementName: {'all': 'Active'}})

    # If we are here it is because elementType is either 'StorageElement' or 'Catalog'
    if elementType == 'StorageElement':
      cs_path = "/Resources/StorageElements"
    elif elementType == 'Catalog':
      cs_path = "/Resources/FileCatalogs"
      statusType = ['Status']

    if not isinstance(elementName, list):
      elementName = [elementName]

    if not isinstance(statusType, list):
      statusType = [statusType]

    result = {}
    for element in elementName:

      for sType in statusType:
        # Look in standard location, 'Active' by default
        res = gConfig.getValue("%s/%s/%s" % (cs_path, element, sType), 'Active')
        result.setdefault(element, {})[sType] = res

    if result:
      return S_OK(result)

    if default is not None:
      defList = [[el, statusType, default] for el in elementName]
      return S_OK(getDictFromList(defList))

    _msg = "Element '%s', with statusType '%s' is unknown for CS."
    return S_ERROR(DErrno.ERESUNK, _msg % (elementName, statusType))

  def __setRSSElementStatus(self, elementName, elementType, statusType, status, reason, tokenOwner):
    """
    Sets on the RSS the Elements status
    """

    expiration = datetime.utcnow() + timedelta(days=1)

    self.rssCache.acquireLock()
    try:
      res = self.rssClient.addOrModifyStatusElement('Resource', 'Status', name=elementName,
                                                    elementType=elementType, status=status,
                                                    statusType=statusType, reason=reason,
                                                    tokenOwner=tokenOwner, tokenExpiration=expiration)

      if res['OK']:
        self.rssCache.refreshCache()

      if not res['OK']:
        _msg = 'Error updating Element (%s,%s,%s)' % (elementName, statusType, status)
        gLogger.warn('RSS: %s' % _msg)

      return res

    finally:
      # Release lock, no matter what.
      self.rssCache.releaseLock()

  def __setCSElementStatus(self, elementName, elementType, statusType, status):
    """
    Sets on the CS the Elements status
    """

    # DIRAC doesn't store the status of ComputingElements nor FTS in the CS, so here we can just do nothing
    if elementType in ('ComputingElement', 'FTS'):
      return S_OK()

    # If we are here it is because elementType is either 'StorageElement' or 'Catalog'
    statuses = self.rssConfig.getConfigStatusType(elementType)
    if statusType not in statuses:
      gLogger.error("%s is not a valid statusType" % statusType)
      return S_ERROR("%s is not a valid statusType: %s" % (statusType, statuses))

    if elementType == 'StorageElement':
      cs_path = "/Resources/StorageElements"
    elif elementType == 'Catalog':
      cs_path = "/Resources/FileCatalogs"
      # FIXME: This a probably outdated location (new one is in /Operations/[]/Services/Catalogs)
      # but needs to be VO-aware
      statusType = 'Status'

    csAPI = CSAPI()
    csAPI.setOption("%s/%s/%s/%s" % (cs_path, elementName, elementType, statusType), status)

    res = csAPI.commitChanges()
    if not res['OK']:
      gLogger.warn('CS: %s' % res['Message'])

    return res

  def __getMode(self):
    """
      Gets flag defined (or not) on the RSSConfiguration.
      If defined as 'Active', we use RSS, if not, we use the CS when possible (and WMS for Sites).
    """

    res = self.rssConfig.getConfigState()

    if res == 'Active':
      if self.rssClient is None:
        self.rssClient = ResourceStatusClient()
      return True

    self.rssClient = None
    return False

  def isStorageElementAlwaysBanned(self, seName, statusType):
    """ Checks if the AlwaysBanned policy is applied to the SE given as parameter

    :param seName: string, name of the SE
    :param statusType: ReadAcces, WriteAccess, RemoveAccess, CheckAccess

    :returns: S_OK(True/False)
    """

    res = getPoliciesThatApply({'name': seName, 'statusType': statusType})
    if not res['OK']:
      self.log.error("isStorageElementAlwaysBanned: unable to get the information", res['Message'])
      return res

    isAlwaysBanned = 'AlwaysBanned' in [policy['type'] for policy in res['Value']]

    return S_OK(isAlwaysBanned)