Example #1
0
class ResourceManagementDB(object):
    """
  The ResourceManagementDB class is a front-end to the ResourceManagementDB MySQL db.
  If exposes four basic methods:

  - insert
  - update
  - get
  - delete

  all them defined on the MySQL monkey class.
  Moreover, there are a set of key-worded parameters that can be used, specially
  on the getX and deleteX functions ( to know more, again, check the MySQL monkey
  documentation ).

  The DB schema has NO foreign keys, so there may be some small consistency checks,
  called validators on the insert and update functions.

  The simplest way to instantiate an object of type :class:`ResourceManagementDB`
  is simply by calling

   >>> rmDB = ResourceManagementDB()

  This way, it will use the standard :mod:`DIRAC.Core.Base.DB`.
  But there's the possibility to use other DB classes.
  For example, we could pass custom DB instantiations to it,
  provided the interface is the same exposed by :mod:`DIRAC.Core.Base.DB`.

   >>> AnotherDB = AnotherDBClass()
   >>> rmDB = ResourceManagementDB( DBin = AnotherDB )

  Alternatively, for testing purposes, you could do:

   >>> from mock import Mock
   >>> mockDB = Mock()
   >>> rmDB = ResourceManagementDB( DBin = mockDB )

  Or, if you want to work with a local DB, providing it's mySQL:

   >>> rmDB = ResourceManagementDB( DBin = [ 'UserName', 'Password' ] )

  The ResourceStatusDB also exposes database Schema information, either on a
  dictionary or on a MySQLSchema tree object.

  - getSchema
  - inspectSchema

  Alternatively, we can access the MySQLSchema XML and tree as follows:

   >>> rmDB = ResourceManagementDB()
   >>> xml  = rmDB.mm.SCHEMA
   >>> tree = rmDB.mm.mSchema
   >>> tree
   >>> tree.
   >>> tree.PolicyResult.Name

  """
    def __init__(self, *args, **kwargs):
        """Constructor."""
        if len(args) == 1:
            if isinstance(args[0], str):
                maxQueueSize = 10
            if isinstance(args[0], int):
                maxQueueSize = args[0]
        elif len(args) == 2:
            maxQueueSize = args[1]
        elif len(args) == 0:
            maxQueueSize = 10

        if 'DBin' in kwargs.keys():
            dbIn = kwargs['DBin']
            if isinstance(dbIn, list):
                from DIRAC.Core.Utilities.MySQL import MySQL
                self.db = MySQL('localhost', dbIn[0], dbIn[1],
                                'ResourceManagementDB')
            else:
                self.db = dbIn
        else:
            from DIRAC.Core.Base.DB import DB
            self.db = DB('ResourceManagementDB',
                         'ResourceStatus/ResourceManagementDB', maxQueueSize)

        self.mm = MySQLMonkey(self)

    @CheckDBExecution
    @ValidateDBTypes
    def insert(self, params, meta):
        """
    Inserts args in the DB making use of kwargs where parameters such as
    the table are specified ( filled automatically by the Client). In order to
    do the insertion, it uses MySQLMonkey to do the parsing, execution and
    error handling. Typically you will not pass kwargs to this function, unless
    you know what are you doing and you have a very special use case.

    :Parameters:
      **params** - `dict`
        arguments for the mysql query ( must match table columns ! ).

      **meta** - `dict`
        metadata for the mysql query. It must contain, at least, `table` key
        with the proper table name.

    :return: S_OK() || S_ERROR()
    """
        return self.mm.insert(params, meta)

    @CheckDBExecution
    @ValidateDBTypes
    def update(self, params, meta):
        """
    Updates row with values given on args. The row selection is done using the
    default of MySQLMonkey ( column.primary or column.keyColumn ). It can be
    modified using kwargs, but it is not explained here. The table keyword
    argument is mandatory, and filled automatically by the Client. Typically
    you will not pass kwargs to this function, unless you know what are you
    doing and you have a very special use case.

    :Parameters:
      **params** - `dict`
        arguments for the mysql query ( must match table columns ! ).

      **meta** - `dict`
        metadata for the mysql query. It must contain, at least, `table` key
        with the proper table name.

    :return: S_OK() || S_ERROR()
    """
        return self.mm.update(params, meta)

    @CheckDBExecution
    @ValidateDBTypes
    def get(self, params, meta):
        """
    Uses arguments to build conditional SQL statement ( WHERE ... ). If the
    sql statement desired is more complex, you can use kwargs to interact with
    the MySQLStatement parser and generate a more sophisticated query.

    :Parameters:
      **params** - `dict`
        arguments for the mysql query ( must match table columns ! ).

      **meta** - `dict`
        metadata for the mysql query. It must contain, at least, `table` key
        with the proper table name.

    :return: S_OK() || S_ERROR()
    """
        return self.mm.get(params, meta)

    @CheckDBExecution
    @ValidateDBTypes
    def delete(self, params, meta):
        """
    Uses arguments to build conditional SQL statement ( WHERE ... ). If the
    sql statement desired is more complex, you can use kwargs to interact with
    the MySQLStatement parser and generate a more sophisticated query. There is
    only one forbidden query, with all parameters None ( this would mean a query
    of the type `DELETE * from TableName` ). The usage of kwargs is the same
    as in the get function.

    :Parameters:
      **params** - `dict`
        arguments for the mysql query ( must match table columns ! ).

      **meta** - `dict`
        metadata for the mysql query. It must contain, at least, `table` key
        with the proper table name.

    :return: S_OK() || S_ERROR()
    """
        return self.mm.delete(params, meta)

    @CheckDBExecution
    def getSchema(self):
        """
    Returns a dictionary with database schema, this includes table and column
    names. It has two variants, columns and keyUsage. The first one has at least,
    as many keys as keyUsage, it is the complete schema. The second one is the
    one used for the default updates and selects -- not taking into account
    auto_increment fields, but taking into account primary and keyUsage fields.

    :Parameters:
      `None`

    :return: S_OK()
    """
        return {'OK': True, 'Value': self.mm.SCHEMA}

    @CheckDBExecution
    def inspectSchema(self):
        """
    Returns an object which represents the database schema and can be browsed.
     >>> db = ResourceManagementDB()
     >>> schema = db.inspectSchema()[ 'Value' ]
     >>> schema
         Schema 123:
         <TableName1>,<TableName2>...
     >>> schema.TableName1
         Table TableName1:
         <ColumnName1>,<ColumnName2>..

    Every column has a few attributes ( primary, keyUsage, extra, position,
    dataType and charMaxLen ).

    :Parameters:
      `None`

    :return: S_OK()
    """
        return {'OK': True, 'Value': self.mm.mSchema}


################################################################################
#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF

################################################################################
## Web functions
################################################################################
#
################################################################################
#
#  def getDownTimesWeb(self, selectDict, _sortList = [], startItem = 0, maxItems = 1000):
#    """
#    Get downtimes registered in the RSS DB (with a web layout)
#
#    :params:
#      :attr:`selectDict`: { 'Granularity':['Site', 'Resource'], 'Severity': ['OUTAGE', 'AT_RISK']}
#
#      :attr:`sortList`
#
#      :attr:`startItem`
#
#      :attr:`maxItems`
#    """
#
#    granularity = selectDict['Granularity']
#    severity = selectDict['Severity']
#
#    if not isinstance(granularity, list):
#      granularity = [granularity]
#    if not isinstance(severity, list):
#      severity = [severity]
#
#    paramNames = ['Granularity', 'Name', 'Severity', 'When']
#
#    req = "SELECT Granularity, Name, Reason FROM PolicyRes WHERE "
#    req = req + "PolicyName LIKE 'DT_%' AND Reason LIKE \'%found%\' "
#    req = req + "AND Granularity in (%s)" %(','.join(['"'+x.strip()+'"' for x in granularity]))
#    resQuery = self.db._query(req)
#    if not resQuery['OK']:
#      raise RSSManagementDBException, resQuery['Message']
#    if not resQuery['Value']:
#      records = []
#    else:
#      resQuery = resQuery['Value']
#      records = []
#      for tuple_ in resQuery:
#        sev = tuple_[2].split()[2]
#        if sev not in severity:
#          continue
#        when = tuple_[2].split(sev)[1][1:]
#        if when == '':
#          when = 'Ongoing'
#        records.append([tuple_[0], tuple_[1], sev, when])
#
#    finalDict = {}
#    finalDict['TotalRecords'] = len(records)
#    finalDict['ParameterNames'] = paramNames
#
#    # Return all the records if maxItems == 0 or the specified number otherwise
#    if maxItems:
#      finalDict['Records'] = records[startItem:startItem+maxItems]
#    else:
#      finalDict['Records'] = records
#
#    finalDict['Extras'] = None
#
#    return finalDict
#
################################################################################
Example #2
0
class ResourceStatusDB(object):
    """
  The ResourceStatusDB class is a front-end to the ResourceStatusDB MySQL db.
  It exposes four basic methods:
  
  - insert
  - update
  - get
  - delete
  
  all them defined on the MySQL monkey class.
  Moreover, there are a set of key-worded parameters that can be used, specially
  on the getX and deleteX functions ( to know more, again, check the MySQL monkey
  documentation ).
  
  The DB schema has NO foreign keys, so there may be some small consistency checks,
  called validators on the insert and update functions.  
  
  The simplest way to instantiate an object of type :class:`ResourceStatusDB`
  is simply by calling

   >>> rsDB = ResourceStatusDB()

  This way, it will use the standard :mod:`DIRAC.Core.Base.DB`.
  But there's the possibility to use other DB classes.
  For example, we could pass custom DB instantiations to it,
  provided the interface is the same exposed by :mod:`DIRAC.Core.Base.DB`.

   >>> AnotherDB = AnotherDBClass()
   >>> rsDB = ResourceStatusDB( DBin = AnotherDB )

  Alternatively, for testing purposes, you could do:

   >>> from mock import Mock
   >>> mockDB = Mock()
   >>> rsDB = ResourceStatusDB( DBin = mockDB )

  Or, if you want to work with a local DB, providing it's mySQL:

   >>> rsDB = ResourceStatusDB( DBin = [ 'UserName', 'Password' ] )
   
  The ResourceStatusDB also exposes database Schema information, either on a 
  dictionary or on a MySQLSchema tree object.
  
  - getSchema
  - inspectSchema
    
  Alternatively, we can access the MySQLSchema XML and tree as follows:
  
   >>> rsDB = ResourceStatusDB()
   >>> xml  = rsDB.mm.SCHEMA
   >>> tree = rsDB.mm.mSchema
   >>> tree
   >>> tree.GridSite
   >>> tree.GridSite.GridTier

  """
    def __init__(self, *args, **kwargs):
        """Constructor."""

        if len(args) == 1:
            if isinstance(args[0], str):
                maxQueueSize = 10
            if isinstance(args[0], int):
                maxQueueSize = args[0]
        elif len(args) == 2:
            maxQueueSize = args[1]
        elif len(args) == 0:
            maxQueueSize = 10

        if 'DBin' in kwargs.keys():
            dbIn = kwargs['DBin']
            if isinstance(dbIn, list):
                from DIRAC.Core.Utilities.MySQL import MySQL
                self.db = MySQL('localhost', dbIn[0], dbIn[1],
                                'ResourceStatusDB')
            else:
                self.db = dbIn
        else:
            from DIRAC.Core.Base.DB import DB
            self.db = DB('ResourceStatusDB', 'ResourceStatus/ResourceStatusDB',
                         maxQueueSize)

        self.mm = MySQLMonkey(self)

    @CheckDBExecution
    @ValidateDBTypes
    def insert(self, params, meta):
        """    
    Inserts args in the DB making use of kwargs where parameters such as
    the table are specified ( filled automatically by the Client). In order to 
    do the insertion, it uses MySQLMonkey to do the parsing, execution and
    error handling. Typically you will not pass kwargs to this function, unless
    you know what are you doing and you have a very special use case.    
      
    :Parameters:
      **params** - `dict`
        arguments for the mysql query ( must match table columns ! ).
    
      **meta** - `dict`
        metadata for the mysql query. It must contain, at least, `table` key
        with the proper table name.

    :return: S_OK() || S_ERROR()
    """
        return self.mm.insert(params, meta)

    @CheckDBExecution
    @ValidateDBTypes
    def update(self, params, meta):
        """    
    Updates row with values given on args. The row selection is done using the
    default of MySQLMonkey ( column.primary or column.keyColumn ). It can be
    modified using kwargs, but it is not explained here. The table keyword 
    argument is mandatory, and filled automatically by the Client. Typically 
    you will not pass kwargs to this function, unless you know what are you 
    doing and you have a very special use case.
       
    :Parameters:
      **params** - `dict`
        arguments for the mysql query ( must match table columns ! ).
    
      **meta** - `dict`
        metadata for the mysql query. It must contain, at least, `table` key
        with the proper table name.

    :return: S_OK() || S_ERROR()
    """
        return self.mm.update(params, meta)

    @CheckDBExecution
    @ValidateDBTypes
    def get(self, params, meta):
        """   
    Uses arguments to build conditional SQL statement ( WHERE ... ). If the 
    sql statement desired is more complex, you can use kwargs to interact with
    the MySQLStatement parser and generate a more sophisticated query.
       
    :Parameters:
      **params** - `dict`
        arguments for the mysql query ( must match table columns ! ).
    
      **meta** - `dict`
        metadata for the mysql query. It must contain, at least, `table` key
        with the proper table name.

    :return: S_OK() || S_ERROR()
    """
        return self.mm.get(params, meta)

    @CheckDBExecution
    @ValidateDBTypes
    def delete(self, params, meta):
        """     
    Uses arguments to build conditional SQL statement ( WHERE ... ). If the 
    sql statement desired is more complex, you can use kwargs to interact with
    the MySQLStatement parser and generate a more sophisticated query. There is
    only one forbidden query, with all parameters None ( this would mean a query
    of the type `DELETE * from TableName` ). The usage of kwargs is the same as in
    the get function.
      
    :Parameters:
      **params** - `dict`
        arguments for the mysql query ( must match table columns ! ).
    
      **meta** - `dict`
        metadata for the mysql query. It must contain, at least, `table` key
        with the proper table name.

    :return: S_OK() || S_ERROR()
    """
        return self.mm.delete(params, meta)

    @CheckDBExecution
    def getSchema(self):
        """      
    Returns a dictionary with database schema, this includes table and column
    names. It has two variants, columns and keyUsage. The first one has at least,
    as many keys as keyUsage, it is the complete schema. The second one is the 
    one used for the default updates and selects -- not taking into account 
    auto_increment fields, but taking into account primary and keyUsage fields.
      
    :Parameters:
      `None`
    
    :return: S_OK()
    """
        return {'OK': True, 'Value': self.mm.SCHEMA}

    @CheckDBExecution
    def inspectSchema(self):
        """     
    Returns an object which represents the database schema and can be browsed.
     >>> db = ResourceStatusDB()
     >>> schema = db.inspectSchema()[ 'Value' ]
     >>> schema
         Schema 123:
         <TableName1>,<TableName2>...
     >>> schema.TableName1
         Table TableName1:
         <ColumnName1>,<ColumnName2>..
    
    Every column has a few attributes ( primary, keyUsage, extra, position,
    dataType and charMaxLen ). 
      
    :Parameters:
      `None`
    
    :return: S_OK()
    """
        return {'OK': True, 'Value': self.mm.mSchema}

        ################################################################
        #                                                              #
        #                    VALIDATION ??                             #
        #                                                              #
        #  o Site             ->(IU) SiteType                          #
        #  o Service          ->(IU) ServiceType, Site                 #
        #  o Resource         ->(IU) ResourceType, ServiceType         #
        #  o StorageElement   ->(IU) Resource                          #
        #  o GridSite         ->(IU) __none__                          #
        #  o *Status          ->(IU) *,StatusType,Status               #
        #  o *ScheduledStatus ->(IU) *,StatusType,Status               #
        #  o *History         ->(IU) *,StatusType,Status               #
        ################################################################


#################################################################################
##EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF

##  '''
##  ##############################################################################
##  # MISC FUNCTIONS
##  ##############################################################################
##  '''
##  Check the booster ResourceStatusSystem.Utilities.ResourceStatusBooster
##  def setMonitoredToBeChecked( self, monitoreds, granularity, name ):
##    """
##    Set LastCheckTime to 0 to monitored(s)
##
##    :params:
##      :attr:`monitoreds`: string, or a list of strings where each is a ValidElement:
##      which granularity has to be set to be checked
##
##      :attr:`granularity`: string, a ValidElement: from who this set comes
##
##      :attr:`name`: string, name of Site or Resource
##    """
##
##    znever = datetime.min
##
##    if type( monitoreds ) is not list:
##      monitoreds = [ monitoreds ]
##
##    for monitored in monitoreds:
##
##      if monitored == 'Site':
##
##        siteName = self.getGeneralName( granularity, name, monitored )[ 'Value' ]
##        self.updateSiteStatus(siteName = siteName, lastCheckTime = znever )
##
##      elif monitored == 'Service' :
##
##        if granularity =='Site':
##          serviceName = self.getMonitoredsList( 'Service', paramsList = [ 'ServiceName' ],
##                                                siteName = name )[ 'Value' ]
##          if type( serviceName ) is not list:
##            serviceName = [ serviceName ]
##          if serviceName != []:
###            raise Exception, where( self, self.setMonitoredToBeChecked ) + " No services for site %s" %name
###          else:
##            serviceName = [ x[0] for x in serviceName ]
##            self.updateServiceStatus( serviceName = serviceName, lastCheckTime = znever )
##        else:
##          serviceName = self.getGeneralName( granularity, name, monitored )[ 'Value' ]
##          self.updateServiceStatus( serviceName = serviceName, lastCheckTime = znever )
##
##      elif monitored == 'Resource':
##
##        if granularity == 'Site' :
##          resourceName = self.getMonitoredsList( 'Resource', paramsList = [ 'ResourceName' ],
##                                                 siteName = name )[ 'Value' ]
##          if type( resourceName ) is not list:
##            resourceName = [ resourceName ]
##          if resourceName != []:
##            #raise Exception, where( self, self.setMonitoredToBeChecked ) + " No resources for site %s" %name
##          #else:
##            resourceName = [ x[0] for x in resourceName ]
##            self.updateResourceStatus( resourceName = resourceName, lastCheckTime = znever )
##
##        elif granularity == 'Service' :
##
##          #siteName = self.getGeneralName( granularity, name, 'Resource' )
##          serviceType, siteName = name.split('@')
##          gridSiteName          = self.getGridSiteName('Site', siteName)[ 'Value' ]
##
##          resourceName = self.getMonitoredsList( monitored, paramsList = [ 'ResourceName' ],
##                                                 gridSiteName = gridSiteName,
##                                                 serviceType = serviceType )[ 'Value' ]
##          if type( resourceName ) is not list:
##            resourceName = [ resourceName ]
##          if resourceName != []:
##         #   raise Exception, where( self, self.setMonitoredToBeChecked ) + " No resources for service %s" %name
##         # else:
##            resourceName = [ x[0] for x in resourceName ]
##            self.updateResourceStatus( resourceName = resourceName, lastCheckTime = znever )
##
##        elif granularity == 'StorageElement':
##          resourceName = self.getGeneralName( granularity,  name, monitored )[ 'Value' ]
##          self.updateResourceStatus( resourceName = resourceName, lastCheckTime = znever )
##
##      # Put read and write together here... too much fomr copy/paste
##      elif monitored == 'StorageElement':
##
##        if granularity == 'Site':
##
##          gridSiteName          = self.getGridSiteName('Site', siteName)[ 'Value' ]
##          SEName = self.getMonitoredsList( monitored, paramsList = [ 'StorageElementName' ],
##                                           gridSiteName = gridSiteName )[ 'Value' ]
##          if type( SEName ) is not list:
##            SEName = [ SEName ]
##          if SEName != []:
##            #pass
##          #else:
##            SEName = [ x[0] for x in SEName ]
##            self.updateStorageElementStatus( storageElementName = SEName, lastCheckTime = znever )
##
##        elif granularity == 'Resource':
##          SEName = self.getMonitoredsList( monitored, paramsList = [ 'StorageElementName' ],
##                                           resourceName = name )[ 'Value' ]
##          if type( SEName ) is not list:
##            SEName = [ SEName ]
##          if SEName == []:
##            pass
###            raise Exception, where(self, self.setMonitoredToBeChecked) + "No storage elements for resource %s" %name
##          else:
##            SEName = [ x[0] for x in SEName ]
##            self.updateStorageElementStatus( storageElementName = SEName, lastCheckTime = znever )
##
##        elif granularity == 'Service':
##
##          serviceType, siteName = name.split('@')
##          gridSiteName          = self.getGridSiteName('Site', siteName)[ 'Value' ]
##
##          SEName = self.getMonitoredsList( monitored, paramsList = [ 'StorageElementName' ],
##                                           gridSiteName = gridSiteName )[ 'Value' ]#name.split('@').pop() )[ 'Value' ]
##          if type( SEName ) is not list:
##            SEName = [ SEName ]
##          if SEName != []:
##            #pass
###            raise Exception, where(self, self.setMonitoredToBeChecked) + "No storage elements for service %s" %name
##          #else:
##            SEName = [ x[0] for x in SEName ]
##            self.updateStorageElementStatus( storageElementName = SEName, lastCheckTime = znever )
################################################################################
#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF
Example #3
0
class ResourceStatusDB( object ):
  """
  The ResourceStatusDB class is a front-end to the ResourceStatusDB MySQL db.
  It exposes four basic methods:
  
  - insert
  - update
  - get
  - delete
  
  all them defined on the MySQL monkey class.
  Moreover, there are a set of key-worded parameters that can be used, specially
  on the getX and deleteX functions ( to know more, again, check the MySQL monkey
  documentation ).
  
  The DB schema has NO foreign keys, so there may be some small consistency checks,
  called validators on the insert and update functions.  
  
  The simplest way to instantiate an object of type :class:`ResourceStatusDB`
  is simply by calling

   >>> rsDB = ResourceStatusDB()

  This way, it will use the standard :mod:`DIRAC.Core.Base.DB`.
  But there's the possibility to use other DB classes.
  For example, we could pass custom DB instantiations to it,
  provided the interface is the same exposed by :mod:`DIRAC.Core.Base.DB`.

   >>> AnotherDB = AnotherDBClass()
   >>> rsDB = ResourceStatusDB( DBin = AnotherDB )

  Alternatively, for testing purposes, you could do:

   >>> from mock import Mock
   >>> mockDB = Mock()
   >>> rsDB = ResourceStatusDB( DBin = mockDB )

  Or, if you want to work with a local DB, providing it's mySQL:

   >>> rsDB = ResourceStatusDB( DBin = [ 'UserName', 'Password' ] )
   
  The ResourceStatusDB also exposes database Schema information, either on a 
  dictionary or on a MySQLSchema tree object.
  
  - getSchema
  - inspectSchema
    
  Alternatively, we can access the MySQLSchema XML and tree as follows:
  
   >>> rsDB = ResourceStatusDB()
   >>> xml  = rsDB.mm.SCHEMA
   >>> tree = rsDB.mm.mSchema
   >>> tree
   >>> tree.GridSite
   >>> tree.GridSite.GridTier

  """ 

  def __init__( self, *args, **kwargs ):
    """Constructor."""

    if len( args ) == 1:
      if isinstance( args[ 0 ], str ):
        maxQueueSize = 10
      if isinstance( args[ 0 ], int ):
        maxQueueSize = args[ 0 ]
    elif len( args ) == 2:
      maxQueueSize = args[ 1 ]
    elif len( args ) == 0:
      maxQueueSize = 10

    if 'DBin' in kwargs.keys():
      dbIn = kwargs[ 'DBin' ]
      if isinstance( dbIn, list ):
        from DIRAC.Core.Utilities.MySQL import MySQL
        self.db = MySQL( 'localhost', dbIn[ 0 ], dbIn[ 1 ], 'ResourceStatusDB' )
      else:
        self.db = dbIn
    else:
      from DIRAC.Core.Base.DB import DB
      self.db = DB( 'ResourceStatusDB', 'ResourceStatus/ResourceStatusDB', maxQueueSize )
   
    self.mm = MySQLMonkey( self )  

  @CheckDBExecution
  @ValidateDBTypes
  def insert( self, params, meta ):
    """    
    Inserts args in the DB making use of kwargs where parameters such as
    the table are specified ( filled automatically by the Client). In order to 
    do the insertion, it uses MySQLMonkey to do the parsing, execution and
    error handling. Typically you will not pass kwargs to this function, unless
    you know what are you doing and you have a very special use case.    
      
    :Parameters:
      **params** - `dict`
        arguments for the mysql query ( must match table columns ! ).
    
      **meta** - `dict`
        metadata for the mysql query. It must contain, at least, `table` key
        with the proper table name.

    :return: S_OK() || S_ERROR()
    """
    return self.mm.insert( params, meta )

  @CheckDBExecution
  @ValidateDBTypes
  def update( self, params, meta ):
    """    
    Updates row with values given on args. The row selection is done using the
    default of MySQLMonkey ( column.primary or column.keyColumn ). It can be
    modified using kwargs, but it is not explained here. The table keyword 
    argument is mandatory, and filled automatically by the Client. Typically 
    you will not pass kwargs to this function, unless you know what are you 
    doing and you have a very special use case.
       
    :Parameters:
      **params** - `dict`
        arguments for the mysql query ( must match table columns ! ).
    
      **meta** - `dict`
        metadata for the mysql query. It must contain, at least, `table` key
        with the proper table name.

    :return: S_OK() || S_ERROR()
    """
    return self.mm.update( params, meta )

  @CheckDBExecution
  @ValidateDBTypes
  def get( self, params, meta ):
    """   
    Uses arguments to build conditional SQL statement ( WHERE ... ). If the 
    sql statement desired is more complex, you can use kwargs to interact with
    the MySQLStatement parser and generate a more sophisticated query.
       
    :Parameters:
      **params** - `dict`
        arguments for the mysql query ( must match table columns ! ).
    
      **meta** - `dict`
        metadata for the mysql query. It must contain, at least, `table` key
        with the proper table name.

    :return: S_OK() || S_ERROR()
    """
    return self.mm.get( params, meta )

  @CheckDBExecution
  @ValidateDBTypes
  def delete( self, params, meta ):
    """     
    Uses arguments to build conditional SQL statement ( WHERE ... ). If the 
    sql statement desired is more complex, you can use kwargs to interact with
    the MySQLStatement parser and generate a more sophisticated query. There is
    only one forbidden query, with all parameters None ( this would mean a query
    of the type `DELETE * from TableName` ). The usage of kwargs is the same as in
    the get function.
      
    :Parameters:
      **params** - `dict`
        arguments for the mysql query ( must match table columns ! ).
    
      **meta** - `dict`
        metadata for the mysql query. It must contain, at least, `table` key
        with the proper table name.

    :return: S_OK() || S_ERROR()
    """
    return self.mm.delete( params, meta )
  
  @CheckDBExecution
  def getSchema( self ):
    """      
    Returns a dictionary with database schema, this includes table and column
    names. It has two variants, columns and keyUsage. The first one has at least,
    as many keys as keyUsage, it is the complete schema. The second one is the 
    one used for the default updates and selects -- not taking into account 
    auto_increment fields, but taking into account primary and keyUsage fields.
      
    :Parameters:
      `None`
    
    :return: S_OK()
    """    
    return { 'OK': True, 'Value' : self.mm.SCHEMA }
    
  @CheckDBExecution  
  def inspectSchema( self ):
    """     
    Returns an object which represents the database schema and can be browsed.
     >>> db = ResourceStatusDB()
     >>> schema = db.inspectSchema()[ 'Value' ]
     >>> schema
         Schema 123:
         <TableName1>,<TableName2>...
     >>> schema.TableName1
         Table TableName1:
         <ColumnName1>,<ColumnName2>..
    
    Every column has a few attributes ( primary, keyUsage, extra, position,
    dataType and charMaxLen ). 
      
    :Parameters:
      `None`
    
    :return: S_OK()
    """    
    return { 'OK': True, 'Value' : self.mm.mSchema }

      ################################################################
      #                                                              #
      #                    VALIDATION ??                             #
      #                                                              #                                       
      #  o Site             ->(IU) SiteType                          #
      #  o Service          ->(IU) ServiceType, Site                 #
      #  o Resource         ->(IU) ResourceType, ServiceType         #
      #  o StorageElement   ->(IU) Resource                          #
      #  o GridSite         ->(IU) __none__                          #
      #  o *Status          ->(IU) *,StatusType,Status               #
      #  o *ScheduledStatus ->(IU) *,StatusType,Status               #
      #  o *History         ->(IU) *,StatusType,Status               #
      ################################################################

#################################################################################
##EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF


##  '''
##  ##############################################################################
##  # MISC FUNCTIONS
##  ##############################################################################
##  '''
##  Check the booster ResourceStatusSystem.Utilities.ResourceStatusBooster
##  def setMonitoredToBeChecked( self, monitoreds, granularity, name ):
##    """
##    Set LastCheckTime to 0 to monitored(s)
##
##    :params:
##      :attr:`monitoreds`: string, or a list of strings where each is a ValidElement:
##      which granularity has to be set to be checked
##
##      :attr:`granularity`: string, a ValidElement: from who this set comes
##
##      :attr:`name`: string, name of Site or Resource
##    """
##
##    znever = datetime.min
##
##    if type( monitoreds ) is not list:
##      monitoreds = [ monitoreds ]
##
##    for monitored in monitoreds:
##
##      if monitored == 'Site':
##
##        siteName = self.getGeneralName( granularity, name, monitored )[ 'Value' ]
##        self.updateSiteStatus(siteName = siteName, lastCheckTime = znever )
##
##      elif monitored == 'Service' :
##
##        if granularity =='Site':
##          serviceName = self.getMonitoredsList( 'Service', paramsList = [ 'ServiceName' ],
##                                                siteName = name )[ 'Value' ]
##          if type( serviceName ) is not list:
##            serviceName = [ serviceName ]
##          if serviceName != []:
###            raise Exception, where( self, self.setMonitoredToBeChecked ) + " No services for site %s" %name
###          else:
##            serviceName = [ x[0] for x in serviceName ]
##            self.updateServiceStatus( serviceName = serviceName, lastCheckTime = znever )
##        else:
##          serviceName = self.getGeneralName( granularity, name, monitored )[ 'Value' ]
##          self.updateServiceStatus( serviceName = serviceName, lastCheckTime = znever )
##
##      elif monitored == 'Resource':
##
##        if granularity == 'Site' :
##          resourceName = self.getMonitoredsList( 'Resource', paramsList = [ 'ResourceName' ],
##                                                 siteName = name )[ 'Value' ]
##          if type( resourceName ) is not list:
##            resourceName = [ resourceName ]
##          if resourceName != []:
##            #raise Exception, where( self, self.setMonitoredToBeChecked ) + " No resources for site %s" %name
##          #else:
##            resourceName = [ x[0] for x in resourceName ]
##            self.updateResourceStatus( resourceName = resourceName, lastCheckTime = znever )
##
##        elif granularity == 'Service' :
##
##          #siteName = self.getGeneralName( granularity, name, 'Resource' )
##          serviceType, siteName = name.split('@')
##          gridSiteName          = self.getGridSiteName('Site', siteName)[ 'Value' ]
##
##          resourceName = self.getMonitoredsList( monitored, paramsList = [ 'ResourceName' ],
##                                                 gridSiteName = gridSiteName,
##                                                 serviceType = serviceType )[ 'Value' ]
##          if type( resourceName ) is not list:
##            resourceName = [ resourceName ]
##          if resourceName != []:
##         #   raise Exception, where( self, self.setMonitoredToBeChecked ) + " No resources for service %s" %name
##         # else:
##            resourceName = [ x[0] for x in resourceName ]
##            self.updateResourceStatus( resourceName = resourceName, lastCheckTime = znever )
##
##        elif granularity == 'StorageElement':
##          resourceName = self.getGeneralName( granularity,  name, monitored )[ 'Value' ]
##          self.updateResourceStatus( resourceName = resourceName, lastCheckTime = znever )
##
##      # Put read and write together here... too much fomr copy/paste
##      elif monitored == 'StorageElement':
##
##        if granularity == 'Site':
##
##          gridSiteName          = self.getGridSiteName('Site', siteName)[ 'Value' ]
##          SEName = self.getMonitoredsList( monitored, paramsList = [ 'StorageElementName' ],
##                                           gridSiteName = gridSiteName )[ 'Value' ]
##          if type( SEName ) is not list:
##            SEName = [ SEName ]
##          if SEName != []:
##            #pass
##          #else:
##            SEName = [ x[0] for x in SEName ]
##            self.updateStorageElementStatus( storageElementName = SEName, lastCheckTime = znever )
##
##        elif granularity == 'Resource':
##          SEName = self.getMonitoredsList( monitored, paramsList = [ 'StorageElementName' ],
##                                           resourceName = name )[ 'Value' ]
##          if type( SEName ) is not list:
##            SEName = [ SEName ]
##          if SEName == []:
##            pass
###            raise Exception, where(self, self.setMonitoredToBeChecked) + "No storage elements for resource %s" %name
##          else:
##            SEName = [ x[0] for x in SEName ]
##            self.updateStorageElementStatus( storageElementName = SEName, lastCheckTime = znever )
##
##        elif granularity == 'Service':
##
##          serviceType, siteName = name.split('@')
##          gridSiteName          = self.getGridSiteName('Site', siteName)[ 'Value' ]
##
##          SEName = self.getMonitoredsList( monitored, paramsList = [ 'StorageElementName' ],
##                                           gridSiteName = gridSiteName )[ 'Value' ]#name.split('@').pop() )[ 'Value' ]
##          if type( SEName ) is not list:
##            SEName = [ SEName ]
##          if SEName != []:
##            #pass
###            raise Exception, where(self, self.setMonitoredToBeChecked) + "No storage elements for service %s" %name
##          #else:
##            SEName = [ x[0] for x in SEName ]
##            self.updateStorageElementStatus( storageElementName = SEName, lastCheckTime = znever )
################################################################################
#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF
class ResourceManagementDB(object):
    """
  The ResourceManagementDB class is a front-end to the ResourceManagementDB MySQL db.
  If exposes four basic methods:

  - insert
  - update
  - get
  - delete

  all them defined on the MySQL monkey class.
  Moreover, there are a set of key-worded parameters that can be used, specially
  on the getX and deleteX functions ( to know more, again, check the MySQL monkey
  documentation ).

  The DB schema has NO foreign keys, so there may be some small consistency checks,
  called validators on the insert and update functions.

  The simplest way to instantiate an object of type :class:`ResourceManagementDB`
  is simply by calling

   >>> rmDB = ResourceManagementDB()

  This way, it will use the standard :mod:`DIRAC.Core.Base.DB`.
  But there's the possibility to use other DB classes.
  For example, we could pass custom DB instantiations to it,
  provided the interface is the same exposed by :mod:`DIRAC.Core.Base.DB`.

   >>> AnotherDB = AnotherDBClass()
   >>> rmDB = ResourceManagementDB( DBin = AnotherDB )

  Alternatively, for testing purposes, you could do:

   >>> from mock import Mock
   >>> mockDB = Mock()
   >>> rmDB = ResourceManagementDB( DBin = mockDB )

  Or, if you want to work with a local DB, providing it's mySQL:

   >>> rmDB = ResourceManagementDB( DBin = [ 'UserName', 'Password' ] )

  The ResourceStatusDB also exposes database Schema information, either on a
  dictionary or on a MySQLSchema tree object.

  - getSchema
  - inspectSchema

  Alternatively, we can access the MySQLSchema XML and tree as follows:

   >>> rmDB = ResourceManagementDB()
   >>> xml  = rmDB.mm.SCHEMA
   >>> tree = rmDB.mm.mSchema
   >>> tree
   >>> tree.
   >>> tree.PolicyResult.Name

  """

    def __init__(self, *args, **kwargs):
        """Constructor."""
        if len(args) == 1:
            if isinstance(args[0], str):
                maxQueueSize = 10
            if isinstance(args[0], int):
                maxQueueSize = args[0]
        elif len(args) == 2:
            maxQueueSize = args[1]
        elif len(args) == 0:
            maxQueueSize = 10

        if "DBin" in kwargs.keys():
            dbIn = kwargs["DBin"]
            if isinstance(dbIn, list):
                from DIRAC.Core.Utilities.MySQL import MySQL

                self.db = MySQL("localhost", dbIn[0], dbIn[1], "ResourceManagementDB")
            else:
                self.db = dbIn
        else:
            from DIRAC.Core.Base.DB import DB

            self.db = DB("ResourceManagementDB", "ResourceStatus/ResourceManagementDB", maxQueueSize)

        self.mm = MySQLMonkey(self)

    @CheckDBExecution
    @ValidateDBTypes
    def insert(self, params, meta):
        """
    Inserts args in the DB making use of kwargs where parameters such as
    the table are specified ( filled automatically by the Client). In order to
    do the insertion, it uses MySQLMonkey to do the parsing, execution and
    error handling. Typically you will not pass kwargs to this function, unless
    you know what are you doing and you have a very special use case.

    :Parameters:
      **params** - `dict`
        arguments for the mysql query ( must match table columns ! ).

      **meta** - `dict`
        metadata for the mysql query. It must contain, at least, `table` key
        with the proper table name.

    :return: S_OK() || S_ERROR()
    """
        return self.mm.insert(params, meta)

    @CheckDBExecution
    @ValidateDBTypes
    def update(self, params, meta):
        """
    Updates row with values given on args. The row selection is done using the
    default of MySQLMonkey ( column.primary or column.keyColumn ). It can be
    modified using kwargs, but it is not explained here. The table keyword
    argument is mandatory, and filled automatically by the Client. Typically
    you will not pass kwargs to this function, unless you know what are you
    doing and you have a very special use case.

    :Parameters:
      **params** - `dict`
        arguments for the mysql query ( must match table columns ! ).

      **meta** - `dict`
        metadata for the mysql query. It must contain, at least, `table` key
        with the proper table name.

    :return: S_OK() || S_ERROR()
    """
        return self.mm.update(params, meta)

    @CheckDBExecution
    @ValidateDBTypes
    def get(self, params, meta):
        """
    Uses arguments to build conditional SQL statement ( WHERE ... ). If the
    sql statement desired is more complex, you can use kwargs to interact with
    the MySQLStatement parser and generate a more sophisticated query.

    :Parameters:
      **params** - `dict`
        arguments for the mysql query ( must match table columns ! ).

      **meta** - `dict`
        metadata for the mysql query. It must contain, at least, `table` key
        with the proper table name.

    :return: S_OK() || S_ERROR()
    """
        return self.mm.get(params, meta)

    @CheckDBExecution
    @ValidateDBTypes
    def delete(self, params, meta):
        """
    Uses arguments to build conditional SQL statement ( WHERE ... ). If the
    sql statement desired is more complex, you can use kwargs to interact with
    the MySQLStatement parser and generate a more sophisticated query. There is
    only one forbidden query, with all parameters None ( this would mean a query
    of the type `DELETE * from TableName` ). The usage of kwargs is the same
    as in the get function.

    :Parameters:
      **params** - `dict`
        arguments for the mysql query ( must match table columns ! ).

      **meta** - `dict`
        metadata for the mysql query. It must contain, at least, `table` key
        with the proper table name.

    :return: S_OK() || S_ERROR()
    """
        return self.mm.delete(params, meta)

    @CheckDBExecution
    def getSchema(self):
        """
    Returns a dictionary with database schema, this includes table and column
    names. It has two variants, columns and keyUsage. The first one has at least,
    as many keys as keyUsage, it is the complete schema. The second one is the
    one used for the default updates and selects -- not taking into account
    auto_increment fields, but taking into account primary and keyUsage fields.

    :Parameters:
      `None`

    :return: S_OK()
    """
        return {"OK": True, "Value": self.mm.SCHEMA}

    @CheckDBExecution
    def inspectSchema(self):
        """
    Returns an object which represents the database schema and can be browsed.
     >>> db = ResourceManagementDB()
     >>> schema = db.inspectSchema()[ 'Value' ]
     >>> schema
         Schema 123:
         <TableName1>,<TableName2>...
     >>> schema.TableName1
         Table TableName1:
         <ColumnName1>,<ColumnName2>..

    Every column has a few attributes ( primary, keyUsage, extra, position,
    dataType and charMaxLen ).

    :Parameters:
      `None`

    :return: S_OK()
    """
        return {"OK": True, "Value": self.mm.mSchema}