You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
433 lines
16 KiB
433 lines
16 KiB
<?php declare(strict_types = 0);
|
|
/*
|
|
** Zabbix
|
|
** Copyright (C) 2001-2023 Zabbix SIA
|
|
**
|
|
** This program is free software; you can redistribute it and/or modify
|
|
** it under the terms of the GNU General Public License as published by
|
|
** the Free Software Foundation; either version 2 of the License, or
|
|
** (at your option) any later version.
|
|
**
|
|
** This program is distributed in the hope that it will be useful,
|
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
** GNU General Public License for more details.
|
|
**
|
|
** You should have received a copy of the GNU General Public License
|
|
** along with this program; if not, write to the Free Software
|
|
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
**/
|
|
|
|
|
|
/**
|
|
* Alert API implementation.
|
|
*/
|
|
class CAlert extends CApiService {
|
|
|
|
public const ACCESS_RULES = [
|
|
'get' => [
|
|
'min_user_type' => USER_TYPE_ZABBIX_USER
|
|
]
|
|
];
|
|
|
|
protected $tableName = 'alerts';
|
|
protected $tableAlias = 'a';
|
|
protected $sortColumns = ['alertid', 'clock', 'eventid', 'status', 'sendto', 'mediatypeid'];
|
|
|
|
public const OUTPUT_FIELDS = ['alertid', 'actionid', 'eventid', 'userid', 'clock', 'mediatypeid', 'sendto',
|
|
'subject', 'message', 'status', 'retries', 'error', 'esc_step', 'alerttype', 'p_eventid', 'acknowledgeid'
|
|
];
|
|
|
|
/**
|
|
* @param array $options
|
|
*
|
|
* @throws APIException
|
|
*
|
|
* @return array|string
|
|
*/
|
|
public function get(array $options = []) {
|
|
$api_input_rules = ['type' => API_OBJECT, 'fields' => [
|
|
// filter
|
|
'alertids' => ['type' => API_IDS, 'flags' => API_ALLOW_NULL | API_NORMALIZE, 'default' => null],
|
|
'groupids' => ['type' => API_IDS, 'flags' => API_ALLOW_NULL | API_NORMALIZE, 'default' => null],
|
|
'hostids' => ['type' => API_IDS, 'flags' => API_ALLOW_NULL | API_NORMALIZE, 'default' => null],
|
|
'objectids' => ['type' => API_IDS, 'flags' => API_ALLOW_NULL | API_NORMALIZE, 'default' => null],
|
|
'actionids' => ['type' => API_IDS, 'flags' => API_ALLOW_NULL | API_NORMALIZE, 'default' => null],
|
|
'eventids' => ['type' => API_IDS, 'flags' => API_ALLOW_NULL | API_NORMALIZE, 'default' => null],
|
|
'mediatypeids' => ['type' => API_IDS, 'flags' => API_ALLOW_NULL | API_NORMALIZE, 'default' => null],
|
|
'userids' => ['type' => API_IDS, 'flags' => API_ALLOW_NULL | API_NORMALIZE, 'default' => null],
|
|
'eventsource' => ['type' => API_INT32, 'in' => implode(',', [EVENT_SOURCE_TRIGGERS, EVENT_SOURCE_DISCOVERY, EVENT_SOURCE_AUTOREGISTRATION, EVENT_SOURCE_INTERNAL, EVENT_SOURCE_SERVICE]), 'default' => EVENT_SOURCE_TRIGGERS],
|
|
'eventobject' => ['type' => API_INT32, 'in' => implode(',', [EVENT_OBJECT_TRIGGER, EVENT_OBJECT_DHOST, EVENT_OBJECT_DSERVICE, EVENT_OBJECT_AUTOREGHOST, EVENT_OBJECT_ITEM, EVENT_OBJECT_LLDRULE, EVENT_OBJECT_SERVICE]), 'default' => EVENT_OBJECT_TRIGGER],
|
|
'time_from' => ['type' => API_TIMESTAMP, 'flags' => API_ALLOW_NULL, 'default' => null],
|
|
'time_till' => ['type' => API_TIMESTAMP, 'flags' => API_ALLOW_NULL, 'default' => null],
|
|
// output
|
|
'output' => ['type' => API_OUTPUT, 'in' => implode(',', self::OUTPUT_FIELDS), 'default' => API_OUTPUT_EXTEND],
|
|
'countOutput' => ['type' => API_FLAG, 'default' => false],
|
|
'groupCount' => ['type' => API_FLAG, 'default' => false],
|
|
'selectHosts' => ['type' => API_OUTPUT, 'flags' => API_ALLOW_NULL, 'in' => implode(',', CHost::OUTPUT_FIELDS), 'default' => null],
|
|
'selectMediatypes' => ['type' => API_OUTPUT, 'flags' => API_ALLOW_NULL, 'in' => implode(',', CMediatype::OUTPUT_FIELDS), 'default' => null],
|
|
'selectUsers' => ['type' => API_OUTPUT, 'flags' => API_ALLOW_NULL, 'in' => implode(',', CUser::OUTPUT_FIELDS), 'default' => null],
|
|
'filter' => ['type' => API_FILTER, 'flags' => API_ALLOW_NULL, 'default' => null, 'fields' => ['alertid', 'actionid', 'eventid', 'userid', 'mediatypeid', 'status', 'acknowledgeid']],
|
|
'search' => ['type' => API_FILTER, 'flags' => API_ALLOW_NULL, 'default' => null, 'fields' => ['sendto', 'subject', 'message', 'error']],
|
|
'searchByAny' => ['type' => API_BOOLEAN, 'default' => false],
|
|
'startSearch' => ['type' => API_FLAG, 'default' => false],
|
|
'excludeSearch' => ['type' => API_FLAG, 'default' => false],
|
|
'searchWildcardsEnabled' => ['type' => API_BOOLEAN, 'default' => false],
|
|
// sort and limit
|
|
'sortfield' => ['type' => API_STRINGS_UTF8, 'flags' => API_NORMALIZE, 'in' => implode(',', $this->sortColumns), 'uniq' => true, 'default' => []],
|
|
'sortorder' => ['type' => API_SORTORDER, 'default' => []],
|
|
'limit' => ['type' => API_INT32, 'flags' => API_ALLOW_NULL, 'in' => '1:'.ZBX_MAX_INT32, 'default' => null],
|
|
// flags
|
|
'editable' => ['type' => API_BOOLEAN, 'default' => false],
|
|
'preservekeys' => ['type' => API_BOOLEAN, 'default' => false],
|
|
'nopermissions' => ['type' => API_BOOLEAN, 'default' => false]
|
|
]];
|
|
|
|
if (!CApiInputValidator::validate($api_input_rules, $options, '/', $error)) {
|
|
self::exception(ZBX_API_ERROR_PARAMETERS, $error);
|
|
}
|
|
|
|
if ($options['output'] === API_OUTPUT_EXTEND) {
|
|
$options['output'] = self::OUTPUT_FIELDS;
|
|
}
|
|
|
|
$res = DBselect($this->createSelectQuery($this->tableName, $options), $options['limit']);
|
|
|
|
$db_alerts = [];
|
|
|
|
while ($row = DBfetch($res)) {
|
|
if ($options['countOutput']) {
|
|
if ($options['groupCount']) {
|
|
$db_alerts[] = $row;
|
|
}
|
|
else {
|
|
$db_alerts = $row['rowscount'];
|
|
}
|
|
}
|
|
else {
|
|
$db_alerts[$row['alertid']] = $row;
|
|
}
|
|
}
|
|
|
|
if ($options['countOutput']) {
|
|
return $db_alerts;
|
|
}
|
|
|
|
if ($db_alerts) {
|
|
$db_alerts = $this->addRelatedObjects($options, $db_alerts);
|
|
$db_alerts = $this->unsetExtraFields($db_alerts, ['alertid', 'userid', 'mediatypeid'], $options['output']);
|
|
|
|
if (!$options['preservekeys']) {
|
|
$db_alerts = array_values($db_alerts);
|
|
}
|
|
}
|
|
|
|
return $db_alerts;
|
|
}
|
|
|
|
protected function applyQueryFilterOptions($table_name, $table_alias, array $options, array $sql_parts): array {
|
|
$sql_parts = parent::applyQueryFilterOptions($table_name, $table_alias, $options, $sql_parts);
|
|
|
|
// editable + PERMISSION CHECK
|
|
if (self::$userData['type'] != USER_TYPE_SUPER_ADMIN && !$options['nopermissions']) {
|
|
// triggers
|
|
if ($options['eventobject'] == EVENT_OBJECT_TRIGGER) {
|
|
$permission = $options['editable'] ? PERM_READ_WRITE : PERM_READ;
|
|
|
|
// Oracle does not support using distinct with nclob fields, so we must use exists instead of joins
|
|
$sql_parts['where'][] = 'EXISTS ('.
|
|
'SELECT NULL'.
|
|
' FROM events e,functions f,items i,hosts_groups hgg'.
|
|
' JOIN rights r'.
|
|
' ON r.id=hgg.groupid'.
|
|
' AND '.dbConditionInt('r.groupid', getUserGroupsByUserId(self::$userData['userid'])).
|
|
' WHERE a.eventid=e.eventid'.
|
|
' AND e.objectid=f.triggerid'.
|
|
' AND f.itemid=i.itemid'.
|
|
' AND i.hostid=hgg.hostid'.
|
|
' GROUP BY f.triggerid'.
|
|
' HAVING MIN(r.permission)>'.PERM_DENY.
|
|
' AND MAX(r.permission)>='.zbx_dbstr($permission).
|
|
')';
|
|
}
|
|
// items and LLD rules
|
|
elseif ($options['eventobject'] == EVENT_OBJECT_ITEM || $options['eventobject'] == EVENT_OBJECT_LLDRULE) {
|
|
$permission = $options['editable'] ? PERM_READ_WRITE : PERM_READ;
|
|
|
|
// Oracle does not support using distinct with nclob fields, so we must use exists instead of joins
|
|
$sql_parts['where'][] = 'EXISTS ('.
|
|
'SELECT NULL'.
|
|
' FROM events e,items i,hosts_groups hgg'.
|
|
' JOIN rights r'.
|
|
' ON r.id=hgg.groupid'.
|
|
' AND '.dbConditionInt('r.groupid', getUserGroupsByUserId(self::$userData['userid'])).
|
|
' WHERE a.eventid=e.eventid'.
|
|
' AND e.objectid=i.itemid'.
|
|
' AND i.hostid=hgg.hostid'.
|
|
' GROUP BY hgg.hostid'.
|
|
' HAVING MIN(r.permission)>'.PERM_DENY.
|
|
' AND MAX(r.permission)>='.zbx_dbstr($permission).
|
|
')';
|
|
}
|
|
}
|
|
|
|
// Oracle does not support using distinct with nclob fields, so we must use exists instead of joins
|
|
if ($options['eventsource'] == EVENT_SOURCE_TRIGGERS
|
|
|| $options['eventsource'] == EVENT_SOURCE_AUTOREGISTRATION) {
|
|
/*
|
|
* Performance optimization: events with such sources does not have multiple objects therefore we can ignore
|
|
* event object in SQL requests.
|
|
*/
|
|
$sql_parts['where'][] = 'EXISTS ('.
|
|
'SELECT NULL'.
|
|
' FROM actions aa'.
|
|
' WHERE a.actionid=aa.actionid'.
|
|
' AND aa.eventsource='.zbx_dbstr($options['eventsource']).
|
|
')';
|
|
}
|
|
else {
|
|
$sql_parts['where'][] = 'EXISTS ('.
|
|
'SELECT NULL'.
|
|
' FROM events e'.
|
|
' WHERE a.eventid=e.eventid'.
|
|
' AND e.source='.zbx_dbstr($options['eventsource']).
|
|
' AND e.object='.zbx_dbstr($options['eventobject']).
|
|
')';
|
|
}
|
|
|
|
// Allow user to get alerts sent only by users with same user group.
|
|
if (self::$userData['type'] != USER_TYPE_SUPER_ADMIN) {
|
|
// Filter by userid only if userid IS NOT NULL.
|
|
$sql_parts['where'][] = '(a.userid IS NULL OR EXISTS ('.
|
|
'SELECT NULL'.
|
|
' FROM users_groups ug'.
|
|
' WHERE ug.userid=a.userid'.
|
|
' AND '.dbConditionInt('ug.usrgrpid', getUserGroupsByUserId(self::$userData['userid'])).
|
|
'))';
|
|
}
|
|
|
|
// groupids
|
|
if ($options['groupids'] !== null) {
|
|
// triggers
|
|
if ($options['eventobject'] == EVENT_OBJECT_TRIGGER) {
|
|
// Oracle does not support using distinct with nclob fields, so we must use exists instead of joins
|
|
$sql_parts['where'][] = 'EXISTS ('.
|
|
'SELECT NULL'.
|
|
' FROM events e,functions f,items i,hosts_groups hg'.
|
|
' WHERE a.eventid=e.eventid'.
|
|
' AND e.objectid=f.triggerid'.
|
|
' AND f.itemid=i.itemid'.
|
|
' AND i.hostid=hg.hostid'.
|
|
' AND '.dbConditionInt('hg.groupid', $options['groupids']).
|
|
')';
|
|
}
|
|
// lld rules and items
|
|
elseif ($options['eventobject'] == EVENT_OBJECT_LLDRULE || $options['eventobject'] == EVENT_OBJECT_ITEM) {
|
|
// Oracle does not support using distinct with nclob fields, so we must use exists instead of joins
|
|
$sql_parts['where'][] = 'EXISTS ('.
|
|
'SELECT NULL'.
|
|
' FROM events e,items i,hosts_groups hg'.
|
|
' WHERE a.eventid=e.eventid'.
|
|
' AND e.objectid=i.itemid'.
|
|
' AND i.hostid=hg.hostid'.
|
|
' AND '.dbConditionInt('hg.groupid', $options['groupids']).
|
|
')';
|
|
}
|
|
}
|
|
|
|
// hostids
|
|
if ($options['hostids'] !== null) {
|
|
// triggers
|
|
if ($options['eventobject'] == EVENT_OBJECT_TRIGGER) {
|
|
// Oracle does not support using distinct with nclob fields, so we must use exists instead of joins
|
|
$sql_parts['where'][] = 'EXISTS ('.
|
|
'SELECT NULL'.
|
|
' FROM events e,functions f,items i'.
|
|
' WHERE a.eventid=e.eventid'.
|
|
' AND e.objectid=f.triggerid'.
|
|
' AND f.itemid=i.itemid'.
|
|
' AND '.dbConditionInt('i.hostid', $options['hostids']).
|
|
')';
|
|
}
|
|
// lld rules and items
|
|
elseif ($options['eventobject'] == EVENT_OBJECT_LLDRULE || $options['eventobject'] == EVENT_OBJECT_ITEM) {
|
|
// Oracle does not support using distinct with nclob fields, so we must use exists instead of joins
|
|
$sql_parts['where'][] = 'EXISTS ('.
|
|
'SELECT NULL'.
|
|
' FROM events e,items i'.
|
|
' WHERE a.eventid=e.eventid'.
|
|
' AND e.objectid=i.itemid'.
|
|
' AND '.dbConditionInt('i.hostid', $options['hostids']).
|
|
')';
|
|
}
|
|
}
|
|
|
|
// alertids
|
|
if ($options['alertids'] !== null) {
|
|
$sql_parts['where'][] = dbConditionInt('a.alertid', $options['alertids']);
|
|
}
|
|
|
|
// objectids
|
|
if ($options['objectids'] !== null && in_array($options['eventobject'],
|
|
[EVENT_OBJECT_TRIGGER, EVENT_OBJECT_ITEM, EVENT_OBJECT_LLDRULE, EVENT_OBJECT_SERVICE])) {
|
|
// Oracle does not support using distinct with nclob fields, so we must use exists instead of joins
|
|
$sql_parts['where'][] = 'EXISTS ('.
|
|
'SELECT NULL'.
|
|
' FROM events e'.
|
|
' WHERE a.eventid=e.eventid'.
|
|
' AND '.dbConditionInt('e.objectid', $options['objectids']).
|
|
')';
|
|
}
|
|
|
|
// eventids
|
|
if ($options['eventids'] !== null) {
|
|
$sql_parts['where'][] = dbConditionInt('a.eventid', $options['eventids']);
|
|
|
|
if ($options['groupCount']) {
|
|
$sql_parts['group']['a'] = 'a.eventid';
|
|
}
|
|
}
|
|
|
|
// actionids
|
|
if ($options['actionids'] !== null) {
|
|
$sql_parts['where'][] = dbConditionInt('a.actionid', $options['actionids']);
|
|
}
|
|
|
|
// userids
|
|
if ($options['userids'] !== null) {
|
|
$field = 'a.userid';
|
|
|
|
if ($options['time_from'] !== null || $options['time_till'] !== null) {
|
|
$field = '(a.userid+0)';
|
|
}
|
|
$sql_parts['where'][] = dbConditionId($field, $options['userids']);
|
|
}
|
|
|
|
// mediatypeids
|
|
if ($options['mediatypeids'] !== null) {
|
|
$sql_parts['where'][] = dbConditionId('a.mediatypeid', $options['mediatypeids']);
|
|
}
|
|
|
|
// time_from
|
|
if ($options['time_from'] !== null) {
|
|
$sql_parts['where'][] = 'a.clock>'.zbx_dbstr($options['time_from']);
|
|
}
|
|
|
|
// time_till
|
|
if ($options['time_till'] !== null) {
|
|
$sql_parts['where'][] = 'a.clock<'.zbx_dbstr($options['time_till']);
|
|
}
|
|
|
|
return $sql_parts;
|
|
}
|
|
|
|
protected function applyQueryOutputOptions($table_name, $table_alias, array $options, array $sql_parts): array {
|
|
$sql_parts = parent::applyQueryOutputOptions($table_name, $table_alias, $options, $sql_parts);
|
|
|
|
if (!$options['countOutput']) {
|
|
if ($options['selectUsers'] !== null) {
|
|
$sql_parts = $this->addQuerySelect($this->fieldId('userid'), $sql_parts);
|
|
}
|
|
|
|
if ($options['selectMediatypes'] !== null) {
|
|
$sql_parts = $this->addQuerySelect($this->fieldId('mediatypeid'), $sql_parts);
|
|
}
|
|
}
|
|
|
|
return $sql_parts;
|
|
}
|
|
|
|
protected function addRelatedObjects(array $options, array $result): array {
|
|
$result = parent::addRelatedObjects($options, $result);
|
|
|
|
self::addRelatedHosts($options, $result);
|
|
$this->addRelatedMediatypes($options, $result);
|
|
$this->addRelatedUsers($options, $result);
|
|
|
|
return $result;
|
|
}
|
|
|
|
private static function addRelatedHosts(array $options, array &$result): void {
|
|
if ($options['selectHosts'] === null) {
|
|
return;
|
|
}
|
|
|
|
$hosts = [];
|
|
$relation_map = new CRelationMap();
|
|
|
|
// trigger events
|
|
if ($options['eventobject'] == EVENT_OBJECT_TRIGGER) {
|
|
$query = DBselect(
|
|
'SELECT a.alertid,i.hostid'.
|
|
' FROM alerts a,events e,functions f,items i'.
|
|
' WHERE '.dbConditionInt('a.alertid', array_keys($result)).
|
|
' AND a.eventid=e.eventid'.
|
|
' AND e.objectid=f.triggerid'.
|
|
' AND f.itemid=i.itemid'.
|
|
' AND e.object='.zbx_dbstr($options['eventobject']).
|
|
' AND e.source='.zbx_dbstr($options['eventsource'])
|
|
);
|
|
}
|
|
// item and LLD rule events
|
|
elseif ($options['eventobject'] == EVENT_OBJECT_ITEM || $options['eventobject'] == EVENT_OBJECT_LLDRULE) {
|
|
$query = DBselect(
|
|
'SELECT a.alertid,i.hostid'.
|
|
' FROM alerts a,events e,items i'.
|
|
' WHERE '.dbConditionInt('a.alertid', array_keys($result)).
|
|
' AND a.eventid=e.eventid'.
|
|
' AND e.objectid=i.itemid'.
|
|
' AND e.object='.zbx_dbstr($options['eventobject']).
|
|
' AND e.source='.zbx_dbstr($options['eventsource'])
|
|
);
|
|
}
|
|
|
|
while ($relation = DBfetch($query)) {
|
|
$relation_map->addRelation($relation['alertid'], $relation['hostid']);
|
|
}
|
|
|
|
$related_ids = $relation_map->getRelatedIds();
|
|
|
|
if ($related_ids) {
|
|
$hosts = API::Host()->get([
|
|
'output' => $options['selectHosts'],
|
|
'hostids' => $related_ids,
|
|
'preservekeys' => true
|
|
]);
|
|
}
|
|
|
|
$result = $relation_map->mapMany($result, $hosts, 'hosts');
|
|
}
|
|
|
|
private function addRelatedMediatypes(array $options, array &$result): void {
|
|
if ($options['selectMediatypes'] === null) {
|
|
return;
|
|
}
|
|
|
|
$relation_map = $this->createRelationMap($result, 'alertid', 'mediatypeid');
|
|
|
|
$mediatypes = API::getApiService()->select('media_type', [
|
|
'output' => $options['selectMediatypes'],
|
|
'filter' => ['mediatypeid' => $relation_map->getRelatedIds()],
|
|
'preservekeys' => true
|
|
]);
|
|
|
|
$result = $relation_map->mapMany($result, $mediatypes, 'mediatypes');
|
|
}
|
|
|
|
private function addRelatedUsers(array $options, array &$result): void {
|
|
if ($options['selectUsers'] === null) {
|
|
return;
|
|
}
|
|
|
|
$relation_map = $this->createRelationMap($result, 'alertid', 'userid');
|
|
|
|
$users = API::User()->get([
|
|
'output' => $options['selectUsers'],
|
|
'userids' => $relation_map->getRelatedIds(),
|
|
'preservekeys' => true
|
|
]);
|
|
|
|
$result = $relation_map->mapMany($result, $users, 'users');
|
|
}
|
|
}
|