""" ResourceStatusClient Client to interact with the ResourceStatus service and from it with the DB. """ # pylint: disable=unused-argument __RCSID__ = "45ddde113 (2021-10-01 11:19:55 +0200) Chris Burr " from DIRAC import S_OK from DIRAC.Core.Base.Client import Client, createClient from DIRAC.ConfigurationSystem.Client.Helpers.Operations import Operations from DIRAC.FrameworkSystem.Client.NotificationClient import NotificationClient from DIRAC.ResourceStatusSystem.Client.ResourceManagementClient import prepareDict @createClient("ResourceStatus/ResourceStatus") class ResourceStatusClient(Client): """ The :class:`ResourceStatusClient` class exposes the :mod:`DIRAC.ResourceStatus` API. All functions you need are on this client. You can use this client on this way >>> from DIRAC.ResourceStatusSystem.Client.ResourceStatusClient import ResourceStatusClient >>> rsClient = ResourceStatusClient() """ def __init__(self, **kwargs): super(ResourceStatusClient, self).__init__(**kwargs) self.setServer("ResourceStatus/ResourceStatus") def insert(self, tableName, record): """ Insert a dictionary `record` as a row in table `tableName` :param str tableName: the name of the table :param dict record: dictionary of record to insert in the table :return: S_OK() || S_ERROR() """ return self._getRPC().insert(tableName, record) def select(self, tableName, params=None): """ Select rows from the table `tableName` :param str tableName: the name of the table :param dict record: dictionary of the selection parameters :return: S_OK() || S_ERROR() """ if params is None: params = {} return self._getRPC().select(tableName, params) def delete(self, tableName, params=None): """ Delect rows from the table `tableName` :param str tableName: the name of the table :param dict record: dictionary of the deletion parameters :Returns: S_OK() || S_ERROR() """ if params is None: params = {} return self._getRPC().delete(tableName, params) ################################################################################ # Element status methods - enjoy ! def insertStatusElement( self, element, tableType, name, statusType, status, elementType, reason, dateEffective, lastCheckTime, tokenOwner, tokenExpiration=None, vO="all", ): """ Inserts on a new row with the arguments given. :Parameters: **element** - `string` it has to be a valid element ( ValidElement ), any of the defaults: `Site` \ | `Resource` | `Node` **tableType** - `string` it has to be a valid tableType [ 'Status', 'Log', 'History' ] **name** - `string` name of the individual of class element **statusType** - `string` it has to be a valid status type for the element class **status** - `string` it has to be a valid status, any of the defaults: `Active` | `Degraded` | \ `Probing` | `Banned` **elementType** - `string` column to distinguish between the different elements in the same element table. **reason** - `string` decision that triggered the assigned status **dateEffective** - `datetime` time-stamp from which the status & status type are effective **lastCheckTime** - `datetime` time-stamp setting last time the status & status were checked **tokenOwner** - `string` token assigned to the site & status type **tokenExpiration** - `datetime` time-stamp setting validity of token ownership :return: S_OK() || S_ERROR() """ columnNames = [ "Name", "StatusType", "Status", "ElementType", "Reason", "DateEffective", "LastCheckTime", "TokenOwner", "TokenExpiration", "VO", ] columnValues = [ name, statusType, status, elementType, reason, dateEffective, lastCheckTime, tokenOwner, tokenExpiration, vO, ] return self._getRPC().insert(element + tableType, prepareDict(columnNames, columnValues)) def selectStatusElement( self, element, tableType, name=None, statusType=None, status=None, elementType=None, reason=None, dateEffective=None, lastCheckTime=None, tokenOwner=None, tokenExpiration=None, meta=None, vO="all", ): """ Gets from all rows that match the parameters given. :Parameters: **element** - `string` it has to be a valid element ( ValidElement ), any of the defaults: `Site` \ | `Resource` | `Node` **tableType** - `string` it has to be a valid tableType [ 'Status', 'Log', 'History' ] **name** - `[, string, list]` name of the individual of class element **statusType** - `[, string, list]` it has to be a valid status type for the element class **status** - `[, string, list]` it has to be a valid status, any of the defaults: `Active` | `Degraded` | \ `Probing` | `Banned` **elementType** - `[, string, list]` column to distinguish between the different elements in the same element table. **reason** - `[, string, list]` decision that triggered the assigned status **dateEffective** - `[, datetime, list]` time-stamp from which the status & status type are effective **lastCheckTime** - `[, datetime, list]` time-stamp setting last time the status & status were checked **tokenOwner** - `[, string, list]` token assigned to the site & status type **tokenExpiration** - `[, datetime, list]` time-stamp setting validity of token ownership **meta** - `dict` metadata for the mysql query. Currently it is being used only for column selection. For example: meta = { 'columns' : [ 'Name' ] } will return only the 'Name' column. :return: S_OK() || S_ERROR() """ columnNames = [ "Name", "StatusType", "Status", "ElementType", "Reason", "DateEffective", "LastCheckTime", "TokenOwner", "TokenExpiration", "Meta", "VO", ] columnValues = [ name, statusType, status, elementType, reason, dateEffective, lastCheckTime, tokenOwner, tokenExpiration, meta, vO, ] return self._getRPC().select(element + tableType, prepareDict(columnNames, columnValues)) def deleteStatusElement( self, element, tableType, name=None, statusType=None, status=None, elementType=None, reason=None, dateEffective=None, lastCheckTime=None, tokenOwner=None, tokenExpiration=None, meta=None, vO="all", ): """ Deletes from all rows that match the parameters given. :Parameters: **element** - `string` it has to be a valid element ( ValidElement ), any of the defaults: `Site` \ | `Resource` | `Node` **tableType** - `string` it has to be a valid tableType [ 'Status', 'Log', 'History' ] **name** - `[, string, list]` name of the individual of class element **statusType** - `[, string, list]` it has to be a valid status type for the element class **status** - `[, string, list]` it has to be a valid status, any of the defaults: `Active` | `Degraded` | \ `Probing` | `Banned` **elementType** - `[, string, list]` column to distinguish between the different elements in the same element table. **reason** - `[, string, list]` decision that triggered the assigned status **dateEffective** - `[, datetime, list]` time-stamp from which the status & status type are effective **lastCheckTime** - `[, datetime, list]` time-stamp setting last time the status & status were checked **tokenOwner** - `[, string, list]` token assigned to the site & status type **tokenExpiration** - `[, datetime, list]` time-stamp setting validity of token ownership **meta** - `dict` metadata for the mysql query :return: S_OK() || S_ERROR() """ columnNames = [ "Name", "StatusType", "Status", "ElementType", "Reason", "DateEffective", "LastCheckTime", "TokenOwner", "TokenExpiration", "Meta", "VO", ] columnValues = [ name, statusType, status, elementType, reason, dateEffective, lastCheckTime, tokenOwner, tokenExpiration, meta, vO, ] return self._getRPC().delete(element + tableType, prepareDict(columnNames, columnValues)) def addOrModifyStatusElement( self, element, tableType, name=None, statusType=None, status=None, elementType=None, reason=None, dateEffective=None, lastCheckTime=None, tokenOwner=None, tokenExpiration=None, vO="all", ): """ Adds or updates-if-duplicated from and also adds a log if flag is active. :Parameters: **element** - `string` it has to be a valid element ( ValidElement ), any of the defaults: `Site` \ | `Resource` | `Node` **tableType** - `string` it has to be a valid tableType [ 'Status', 'Log', 'History' ] **name** - `string` name of the individual of class element **statusType** - `string` it has to be a valid status type for the element class **status** - `string` it has to be a valid status, any of the defaults: `Active` | `Degraded` | \ `Probing` | `Banned` **elementType** - `string` column to distinguish between the different elements in the same element table. **reason** - `string` decision that triggered the assigned status **dateEffective** - `datetime` time-stamp from which the status & status type are effective **lastCheckTime** - `datetime` time-stamp setting last time the status & status were checked **tokenOwner** - `string` token assigned to the site & status type **tokenExpiration** - `datetime` time-stamp setting validity of token ownership :return: S_OK() || S_ERROR() """ columnNames = [ "Name", "StatusType", "Status", "ElementType", "Reason", "DateEffective", "LastCheckTime", "TokenOwner", "TokenExpiration", "VO", ] columnValues = [ name, statusType, status, elementType, reason, dateEffective, lastCheckTime, tokenOwner, tokenExpiration, vO, ] return self._getRPC().addOrModify(element + tableType, prepareDict(columnNames, columnValues)) def modifyStatusElement( self, element, tableType, name=None, statusType=None, status=None, elementType=None, reason=None, dateEffective=None, lastCheckTime=None, tokenOwner=None, tokenExpiration=None, vO="all", ): """ Updates from and also adds a log if flag is active. :Parameters: **element** - `string` it has to be a valid element ( ValidElement ), any of the defaults: `Site` \ | `Resource` | `Node` **tableType** - `string` it has to be a valid tableType [ 'Status', 'Log', 'History' ] **name** - `string` name of the individual of class element **statusType** - `string` it has to be a valid status type for the element class **status** - `string` it has to be a valid status, any of the defaults: `Active` | `Degraded` | \ `Probing` | `Banned` **elementType** - `string` column to distinguish between the different elements in the same element table. **reason** - `string` decision that triggered the assigned status **dateEffective** - `datetime` time-stamp from which the status & status type are effective **lastCheckTime** - `datetime` time-stamp setting last time the status & status were checked **tokenOwner** - `string` token assigned to the site & status type **tokenExpiration** - `datetime` time-stamp setting validity of token ownership :return: S_OK() || S_ERROR() """ columnNames = [ "Name", "StatusType", "Status", "ElementType", "Reason", "DateEffective", "LastCheckTime", "TokenOwner", "TokenExpiration", "VO", ] columnValues = [ name, statusType, status, elementType, reason, dateEffective, lastCheckTime, tokenOwner, tokenExpiration, vO, ] return self._getRPC().addOrModify(element + tableType, prepareDict(columnNames, columnValues)) def addIfNotThereStatusElement( self, element, tableType, name=None, statusType=None, status=None, elementType=None, reason=None, dateEffective=None, lastCheckTime=None, tokenOwner=None, tokenExpiration=None, vO="all", ): """ Adds if-not-duplicated from and also adds a log if flag is active. :Parameters: **element** - `string` it has to be a valid element ( ValidElement ), any of the defaults: `Site` \ | `Resource` | `Node` **tableType** - `string` it has to be a valid tableType [ 'Status', 'Log', 'History' ] **name** - `string` name of the individual of class element **statusType** - `string` it has to be a valid status type for the element class **status** - `string` it has to be a valid status, any of the defaults: `Active` | `Degraded` | \ `Probing` | `Banned` **elementType** - `string` column to distinguish between the different elements in the same element table. **reason** - `string` decision that triggered the assigned status **dateEffective** - `datetime` time-stamp from which the status & status type are effective **lastCheckTime** - `datetime` time-stamp setting last time the status & status were checked **tokenOwner** - `string` token assigned to the site & status type **tokenExpiration** - `datetime` time-stamp setting validity of token ownership :return: S_OK() || S_ERROR() """ columnNames = [ "Name", "StatusType", "Status", "ElementType", "Reason", "DateEffective", "LastCheckTime", "TokenOwner", "TokenExpiration", "VO", ] columnValues = [ name, statusType, status, elementType, reason, dateEffective, lastCheckTime, tokenOwner, tokenExpiration, vO, ] return self._getRPC().addIfNotThere(element + tableType, prepareDict(columnNames, columnValues)) ############################################################################## # Protected methods - Use carefully !! def notify(self, request, params): """Send notification for a given request with its params to the diracAdmin""" address = Operations().getValue("ResourceStatus/Notification/DebugGroup/Users") msg = "Matching parameters: " + str(params) sbj = "[NOTIFICATION] DIRAC ResourceStatusDB: " + request + " entry" NotificationClient().sendMail(address, sbj, msg, address) def _extermineStatusElement(self, element, name, keepLogs=True): """ Deletes from Status, History Log all rows with `elementName`. It removes all the entries, logs, etc.. Use with common sense ! :Parameters: **element** - `string` it has to be a valid element ( ValidElements ), any of the defaults: \ `Site` | `Resource` | `Node` **name** - `[, string, list]` name of the individual of class element **keepLogs** - `bool` if active, logs are kept in the database :return: S_OK() || S_ERROR() """ return self.__extermineStatusElement(element, name, keepLogs) def __extermineStatusElement(self, element, name, keepLogs): """ This method iterates over the three ( or four ) table types - depending on the value of keepLogs - deleting all matches of `name`. """ tableTypes = ["Status", "History"] if keepLogs is False: tableTypes.append("Log") for table in tableTypes: deleteQuery = self.deleteStatusElement(element, table, name=name) if not deleteQuery["OK"]: return deleteQuery return S_OK() ################################################################################ # EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF#EOF