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.

2130 lines
67 KiB

<?php
/*
** 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.
**/
function condition_operator2str($operator = null) {
$operators = [
CONDITION_OPERATOR_EQUAL => _('equals'),
CONDITION_OPERATOR_NOT_EQUAL => _('does not equal'),
CONDITION_OPERATOR_LIKE => _('contains'),
CONDITION_OPERATOR_NOT_LIKE => _('does not contain'),
CONDITION_OPERATOR_IN => _('in'),
CONDITION_OPERATOR_MORE_EQUAL => _('is greater than or equals'),
CONDITION_OPERATOR_LESS_EQUAL => _('is less than or equals'),
CONDITION_OPERATOR_NOT_IN => _('not in'),
CONDITION_OPERATOR_YES => _('Yes'),
CONDITION_OPERATOR_NO => _('No'),
CONDITION_OPERATOR_REGEXP => _('matches'),
CONDITION_OPERATOR_NOT_REGEXP => _('does not match')
];
return $operator !== null
? $operators[$operator]
: $operators;
}
function condition_type2str($type = null) {
$types = [
CONDITION_TYPE_SUPPRESSED => _('Problem is suppressed'),
CONDITION_TYPE_TRIGGER_NAME => _('Trigger name'),
CONDITION_TYPE_TRIGGER_SEVERITY => _('Trigger severity'),
CONDITION_TYPE_TRIGGER => _('Trigger'),
CONDITION_TYPE_HOST_NAME => _('Host name'),
CONDITION_TYPE_HOST_GROUP => _('Host group'),
CONDITION_TYPE_TEMPLATE => _('Template'),
CONDITION_TYPE_HOST => _('Host'),
CONDITION_TYPE_TIME_PERIOD => _('Time period'),
CONDITION_TYPE_DRULE => _('Discovery rule'),
CONDITION_TYPE_DCHECK => _('Discovery check'),
CONDITION_TYPE_DOBJECT => _('Discovery object'),
CONDITION_TYPE_DHOST_IP => _('Host IP'),
CONDITION_TYPE_DSERVICE_TYPE => _('Service type'),
CONDITION_TYPE_DSERVICE_PORT => _('Service port'),
CONDITION_TYPE_DSTATUS => _('Discovery status'),
CONDITION_TYPE_DUPTIME => _('Uptime/Downtime'),
CONDITION_TYPE_DVALUE => _('Received value'),
CONDITION_TYPE_EVENT_ACKNOWLEDGED => _('Event acknowledged'),
CONDITION_TYPE_PROXY => _('Proxy'),
CONDITION_TYPE_EVENT_TYPE => _('Event type'),
CONDITION_TYPE_HOST_METADATA => _('Host metadata'),
CONDITION_TYPE_EVENT_TAG => _('Tag name'),
CONDITION_TYPE_EVENT_TAG_VALUE => _('Tag value'),
CONDITION_TYPE_SERVICE => _('Service'),
CONDITION_TYPE_SERVICE_NAME => _('Service name')
];
return $type !== null
? $types[$type]
: $types;
}
function discovery_object2str($object = null) {
$objects = [
EVENT_OBJECT_DHOST => _('Device'),
EVENT_OBJECT_DSERVICE => _('Service')
];
if ($object === null) {
return $objects;
}
return $objects[$object];
}
/**
* Converts numerical action condition values to their corresponding string values according to action condition type.
*
* For action condition types such as: hosts, host groups, templates, proxies, triggers, discovery rules
* and discovery checks, action condition values contain IDs. All unique IDs are first collected and then queried.
* For other action condition types values are returned as they are or converted using simple string conversion
* functions according to action condition type.
*
* @param array $actions Array of actions.
* array $action['filter'] Array containing arrays of action conditions and other data.
* array $action['filter']['conditions'] Array of action conditions.
*
* @return array Returns an array of actions condition string values.
*/
function actionConditionValueToString(array $actions) {
$result = [];
$groupIds = [];
$triggerIds = [];
$hostIds = [];
$templateIds = [];
$proxyIds = [];
$dRuleIds = [];
$dCheckIds = [];
$serviceids = [];
foreach ($actions as $i => $action) {
$result[$i] = [];
foreach ($action['filter']['conditions'] as $j => $condition) {
// Unknown types and all the default values for other types are 'Unknown'.
$result[$i][$j] = _('Unknown');
switch ($condition['conditiontype']) {
case CONDITION_TYPE_HOST_GROUP:
$groupIds[$condition['value']] = $condition['value'];
break;
case CONDITION_TYPE_TRIGGER:
$triggerIds[$condition['value']] = $condition['value'];
break;
case CONDITION_TYPE_HOST:
$hostIds[$condition['value']] = $condition['value'];
break;
case CONDITION_TYPE_TEMPLATE:
$templateIds[$condition['value']] = $condition['value'];
break;
case CONDITION_TYPE_PROXY:
$proxyIds[$condition['value']] = $condition['value'];
break;
case CONDITION_TYPE_SERVICE:
$serviceids[$condition['value']] = $condition['value'];
break;
// return values as is for following condition types
case CONDITION_TYPE_TRIGGER_NAME:
case CONDITION_TYPE_HOST_METADATA:
case CONDITION_TYPE_HOST_NAME:
case CONDITION_TYPE_TIME_PERIOD:
case CONDITION_TYPE_DHOST_IP:
case CONDITION_TYPE_DSERVICE_PORT:
case CONDITION_TYPE_DUPTIME:
case CONDITION_TYPE_DVALUE:
case CONDITION_TYPE_EVENT_TAG:
case CONDITION_TYPE_EVENT_TAG_VALUE:
case CONDITION_TYPE_SERVICE_NAME:
$result[$i][$j] = $condition['value'];
break;
case CONDITION_TYPE_EVENT_ACKNOWLEDGED:
$result[$i][$j] = $condition['value'] ? _('Ack') : _('Not Ack');
break;
case CONDITION_TYPE_TRIGGER_SEVERITY:
$result[$i][$j] = CSeverityHelper::getName((int) $condition['value']);
break;
case CONDITION_TYPE_DRULE:
$dRuleIds[$condition['value']] = $condition['value'];
break;
case CONDITION_TYPE_DCHECK:
$dCheckIds[$condition['value']] = $condition['value'];
break;
case CONDITION_TYPE_DOBJECT:
$result[$i][$j] = discovery_object2str($condition['value']);
break;
case CONDITION_TYPE_DSERVICE_TYPE:
$result[$i][$j] = discovery_check_type2str($condition['value']);
break;
case CONDITION_TYPE_DSTATUS:
$result[$i][$j] = discovery_object_status2str($condition['value']);
break;
case CONDITION_TYPE_EVENT_TYPE:
$result[$i][$j] = eventType($condition['value']);
break;
}
}
}
$groups = [];
$triggers = [];
$hosts = [];
$templates = [];
$proxies = [];
$dRules = [];
$dChecks = [];
$services = [];
if ($groupIds) {
$groups = API::HostGroup()->get([
'output' => ['name'],
'groupids' => $groupIds,
'preservekeys' => true
]);
}
if ($triggerIds) {
$triggers = API::Trigger()->get([
'output' => ['description'],
'triggerids' => $triggerIds,
'expandDescription' => true,
'selectHosts' => ['name'],
'preservekeys' => true
]);
}
if ($hostIds) {
$hosts = API::Host()->get([
'output' => ['name'],
'hostids' => $hostIds,
'preservekeys' => true
]);
}
if ($templateIds) {
$templates = API::Template()->get([
'output' => ['name'],
'templateids' => $templateIds,
'preservekeys' => true
]);
}
if ($proxyIds) {
$proxies = API::Proxy()->get([
'output' => ['name'],
'proxyids' => $proxyIds,
'preservekeys' => true
]);
}
if ($dRuleIds) {
$dRules = API::DRule()->get([
'output' => ['name'],
'druleids' => $dRuleIds,
'preservekeys' => true
]);
}
if ($dCheckIds) {
$dChecks = API::DCheck()->get([
'output' => ['type', 'key_', 'ports', 'allow_redirect'],
'dcheckids' => $dCheckIds,
'selectDRules' => ['name'],
'preservekeys' => true
]);
}
if ($serviceids) {
$services = API::Service()->get([
'output' => ['name'],
'serviceids' => $serviceids,
'preservekeys' => true
]);
}
if ($groups || $triggers || $hosts || $templates || $proxies || $dRules || $dChecks || $services) {
foreach ($actions as $i => $action) {
foreach ($action['filter']['conditions'] as $j => $condition) {
$id = $condition['value'];
switch ($condition['conditiontype']) {
case CONDITION_TYPE_HOST_GROUP:
if (array_key_exists($id, $groups)) {
$result[$i][$j] = $groups[$id]['name'];
}
break;
case CONDITION_TYPE_TRIGGER:
if (array_key_exists($id, $triggers)) {
$host = reset($triggers[$id]['hosts']);
$result[$i][$j] = $host['name'].NAME_DELIMITER.$triggers[$id]['description'];
}
break;
case CONDITION_TYPE_HOST:
if (array_key_exists($id, $hosts)) {
$result[$i][$j] = $hosts[$id]['name'];
}
break;
case CONDITION_TYPE_TEMPLATE:
if (array_key_exists($id, $templates)) {
$result[$i][$j] = $templates[$id]['name'];
}
break;
case CONDITION_TYPE_PROXY:
if (array_key_exists($id, $proxies)) {
$result[$i][$j] = $proxies[$id]['name'];
}
break;
case CONDITION_TYPE_DRULE:
if (array_key_exists($id, $dRules)) {
$result[$i][$j] = $dRules[$id]['name'];
}
break;
case CONDITION_TYPE_DCHECK:
if (array_key_exists($id, $dChecks)) {
$drule = reset($dChecks[$id]['drules']);
$type = $dChecks[$id]['type'];
$key_ = $dChecks[$id]['key_'];
$ports = $dChecks[$id]['ports'];
$allow_redirect = $dChecks[$id]['allow_redirect'];
$dCheck = discovery_check2str($type, $key_, $ports, $allow_redirect);
$result[$i][$j] = $drule['name'].NAME_DELIMITER.$dCheck;
}
break;
case CONDITION_TYPE_SERVICE:
if (array_key_exists($id, $services)) {
$result[$i][$j] = $services[$id]['name'];
}
break;
}
}
}
}
return $result;
}
/**
* Returns the HTML representation of an action condition and action operation condition.
*
* @param string $condition_type
* @param string $operator
* @param string $value
* @param string $value2
*
* @return array|string
*/
function getConditionDescription($condition_type, $operator, $value, $value2) {
if ($condition_type == CONDITION_TYPE_EVENT_TAG_VALUE) {
$description = [_('Value of tag')];
$description[] = ' ';
$description[] = italic($value2);
$description[] = ' ';
}
elseif ($condition_type == CONDITION_TYPE_SUPPRESSED) {
return ($operator == CONDITION_OPERATOR_YES)
? [_('Problem is suppressed')]
: [_('Problem is not suppressed')];
}
elseif ($condition_type == CONDITION_TYPE_EVENT_ACKNOWLEDGED) {
return $value ? _('Event is acknowledged') : _('Event is not acknowledged');
}
else {
$description = [condition_type2str($condition_type)];
$description[] = ' ';
}
$description[] = condition_operator2str($operator);
$description[] = ' ';
$description[] = italic($value);
return $description;
}
/**
* Gathers operation data and processes it based on operation type.
*
* @param array $operations Array of operations.
*
* @return array Returns an array of processed data.
*/
function getActionOperationData(array $operations): array {
$result = [];
$data = [];
foreach ($operations as $operation) {
switch ($operation['operationtype']) {
case OPERATION_TYPE_MESSAGE:
if ($operation['opmessage']['mediatypeid'] != 0) {
$data['mediatypeids'][$operation['opmessage']['mediatypeid']] = true;
}
if (array_key_exists('opmessage_usr', $operation) && $operation['opmessage_usr']) {
foreach ($operation['opmessage_usr'] as $users) {
$data['userids'][$users['userid']] = true;
}
}
if (array_key_exists('opmessage_grp', $operation) && $operation['opmessage_grp']) {
foreach ($operation['opmessage_grp'] as $user_groups) {
$data['usrgrpids'][$user_groups['usrgrpid']] = true;
}
}
break;
case OPERATION_TYPE_COMMAND:
if (array_key_exists('opcommand_hst', $operation) && $operation['opcommand_hst']) {
foreach ($operation['opcommand_hst'] as $host) {
if ($host['hostid'] != 0) {
$data['hostids'][$host['hostid']] = true;
}
}
}
if (array_key_exists('opcommand_grp', $operation) && $operation['opcommand_grp']) {
foreach ($operation['opcommand_grp'] as $host_group) {
$data['groupids'][$host_group['groupid']] = true;
}
}
$data['scriptids'][$operation['opcommand']['scriptid']] = true;
break;
case OPERATION_TYPE_GROUP_ADD:
case OPERATION_TYPE_GROUP_REMOVE:
foreach ($operation['opgroup'] as $groupid) {
$data['groupids'][$groupid['groupid']] = true;
}
break;
case OPERATION_TYPE_TEMPLATE_ADD:
case OPERATION_TYPE_TEMPLATE_REMOVE:
foreach ($operation['optemplate'] as $templateid) {
$data['templateids'][$templateid['templateid']] = true;
}
break;
}
}
if (array_key_exists('mediatypeids', $data)) {
$result['mediatypes'] = API::Mediatype()->get([
'output' => ['name'],
'mediatypeids' => array_keys($data['mediatypeids']),
'preservekeys' => true
]);
}
if (array_key_exists('userids', $data)) {
$users = API::User()->get([
'output' => ['userid', 'username', 'name', 'surname'],
'userids' => array_keys($data['userids'])
]);
foreach ($users as $user) {
$result['users'][$user['userid']]['name'] = getUserFullname($user);
}
}
if (array_key_exists('usrgrpids', $data)) {
$result['user_groups'] = API::UserGroup()->get([
'output' => ['name'],
'usrgrpids' => array_keys($data['usrgrpids']),
'preservekeys' => true
]);
}
if (array_key_exists('hostids', $data)) {
$result['hosts'] = API::Host()->get([
'output' => ['name'],
'hostids' => array_keys($data['hostids']),
'preservekeys' => true
]);
}
if (array_key_exists('groupids', $data)) {
$result['host_groups'] = API::HostGroup()->get([
'output' => ['name'],
'groupids' => array_keys($data['groupids']),
'preservekeys' => true
]);
}
if (array_key_exists('templateids', $data)) {
$result['templates'] = API::Template()->get([
'output' => ['name'],
'templateids' => array_keys($data['templateids']),
'preservekeys' => true
]);
}
if (array_key_exists('scriptids', $data)) {
$result['scripts'] = API::Script()->get([
'output' => ['name'],
'scriptids' => array_keys($data['scriptids']),
'filter' => ['scope' => ZBX_SCRIPT_SCOPE_ACTION],
'preservekeys' => true
]);
}
return $result;
}
/**
* Formats the HTML representation of action operation values according to action operation type.
*
* @param array $operations Array of operations.
* @param int $eventsource Actions eventsource.
* @param array $operation_values All processed data of operation values.
*
* @return array Returns an array of actions operation descriptions.
*/
function getActionOperationDescriptions(array $operations, int $eventsource, array $operation_values): array {
$result = [];
$mediatypes = array_key_exists('mediatypes', $operation_values) ? $operation_values['mediatypes'] : [];
$users = array_key_exists('users', $operation_values) ? $operation_values['users'] : [];
$user_groups = array_key_exists('user_groups', $operation_values) ? $operation_values['user_groups'] : [];
$hosts = array_key_exists('hosts', $operation_values) ? $operation_values['hosts'] : [];
$host_groups = array_key_exists('host_groups', $operation_values) ? $operation_values['host_groups'] : [];
$templates = array_key_exists('templates', $operation_values) ? $operation_values['templates'] : [];
$scripts = array_key_exists('scripts', $operation_values) ? $operation_values['scripts'] : [];
foreach ($operations as $i => $operation) {
switch ($operation['operationtype']) {
case OPERATION_TYPE_MESSAGE:
$mediatype = _('all media');
$mediatypeid = $operation['opmessage']['mediatypeid'];
if ($mediatypeid != 0 && array_key_exists($mediatypeid, $mediatypes)) {
$mediatype = $mediatypes[$mediatypeid]['name'];
}
if (array_key_exists('opmessage_usr', $operation) && $operation['opmessage_usr']) {
$user_names_list = [];
foreach ($operation['opmessage_usr'] as $user) {
if (array_key_exists($user['userid'], $users)){
$user_names_list[] = $users[$user['userid']]['name'];
}
}
order_result($user_names_list);
$result[$i][] = bold(_('Send message to users').': ');
$result[$i][] = [implode(', ', $user_names_list), ' ', _('via'), ' ', $mediatype];
$result[$i][] = BR();
}
if (array_key_exists('opmessage_grp', $operation) && $operation['opmessage_grp']) {
$user_groups_list = [];
foreach ($operation['opmessage_grp'] as $user_group) {
if (array_key_exists($user_group['usrgrpid'], $user_groups)) {
$user_groups_list[] = $user_groups[$user_group['usrgrpid']]['name'];
}
}
order_result($user_groups_list);
$result[$i][] = bold(_('Send message to user groups').': ');
$result[$i][] = [implode(', ', $user_groups_list), ' ', _('via'), ' ', $mediatype];
$result[$i][] = BR();
}
break;
case OPERATION_TYPE_COMMAND:
$scriptid = $operation['opcommand']['scriptid'];
if ($eventsource == EVENT_SOURCE_SERVICE) {
$result[$i][] = [
bold(_s('Run script "%1$s" on Zabbix server', $scripts[$scriptid]['name'])),
BR()
];
break;
}
if (array_key_exists('opcommand_hst', $operation) && $operation['opcommand_hst']) {
$host_list = [];
foreach ($operation['opcommand_hst'] as $host) {
if ($host['hostid'] == 0) {
$result[$i][] = [
bold(_s('Run script "%1$s" on current host', $scripts[$scriptid]['name'])),
BR()
];
}
elseif (array_key_exists($host['hostid'], $hosts)) {
$host_list[] = $hosts[$host['hostid']]['name'];
}
}
if ($host_list) {
order_result($host_list);
$result[$i][] = bold(
_s('Run script "%1$s" on hosts', $scripts[$scriptid]['name']).': '
);
$result[$i][] = [implode(', ', $host_list), BR()];
}
}
if (array_key_exists('opcommand_grp', $operation) && $operation['opcommand_grp']) {
$host_group_list = [];
foreach ($operation['opcommand_grp'] as $host_group) {
if (array_key_exists($host_group['groupid'], $host_groups)) {
$host_group_list[] = $host_groups[$host_group['groupid']]['name'];
}
}
order_result($host_group_list);
$result[$i][] = bold(
_s('Run script "%1$s" on host groups', $scripts[$scriptid]['name']).': '
);
$result[$i][] = [implode(', ', $host_group_list), BR()];
}
break;
case OPERATION_TYPE_HOST_ADD:
$result[$i][] = [bold(_('Add host')), BR()];
break;
case OPERATION_TYPE_HOST_REMOVE:
$result[$i][] = [bold(_('Remove host')), BR()];
break;
case OPERATION_TYPE_HOST_TAGS_ADD:
case OPERATION_TYPE_HOST_TAGS_REMOVE:
$tags = [];
if (array_key_exists('optag', $operation) && $operation['optag']) {
CArrayHelper::sort($operation['optag'], ['tag', 'value']);
foreach ($operation['optag'] as $tag) {
$value = getTagString($tag);
if ($value !== '') {
$tags[] = (new CSpan($value))
->addClass(ZBX_STYLE_TAG)
->setHint(getTagString($tag));
}
}
if ($operation['operationtype'] == OPERATION_TYPE_HOST_TAGS_ADD) {
$result[$i][] = bold(_('Add host tags').': ');
}
else {
$result[$i][] = bold(_('Remove host tags').': ');
}
}
$result[$i][] = [$tags, BR()];
break;
case OPERATION_TYPE_HOST_ENABLE:
$result[$i][] = [bold(_('Enable host')), BR()];
break;
case OPERATION_TYPE_HOST_DISABLE:
$result[$i][] = [bold(_('Disable host')), BR()];
break;
case OPERATION_TYPE_GROUP_ADD:
case OPERATION_TYPE_GROUP_REMOVE:
$host_group_list = [];
foreach ($operation['opgroup'] as $groupid) {
if (array_key_exists($groupid['groupid'], $host_groups)) {
$host_group_list[] = $host_groups[$groupid['groupid']]['name'];
}
}
order_result($host_group_list);
if ($operation['operationtype'] == OPERATION_TYPE_GROUP_ADD) {
$result[$i][] = bold(_('Add to host groups').': ');
}
else {
$result[$i][] = bold(_('Remove from host groups').': ');
}
$result[$i][] = [implode(', ', $host_group_list), BR()];
break;
case OPERATION_TYPE_TEMPLATE_ADD:
case OPERATION_TYPE_TEMPLATE_REMOVE:
$template_list = [];
foreach ($operation['optemplate'] as $templateid) {
if (array_key_exists($templateid['templateid'], $templates)) {
$template_list[] = $templates[$templateid['templateid']]['name'];
}
}
order_result($template_list);
if ($operation['operationtype'] == OPERATION_TYPE_TEMPLATE_ADD) {
$result[$i][] = bold(_('Link templates').': ');
}
else {
$result[$i][] = bold(_('Unlink templates').': ');
}
$result[$i][] = [implode(', ', $template_list), BR()];
break;
case OPERATION_TYPE_HOST_INVENTORY:
$host_inventory_modes = getHostInventoryModes();
$result[$i][] = bold(operation_type2str(OPERATION_TYPE_HOST_INVENTORY).': ');
$result[$i][] = [$host_inventory_modes[$operation['opinventory']['inventory_mode']], BR()];
break;
case OPERATION_TYPE_RECOVERY_MESSAGE:
case OPERATION_TYPE_UPDATE_MESSAGE:
$result[$i][] = bold(_('Notify all involved'));
break;
}
}
return $result;
}
/**
* Return an array of action conditions supported by the given event source.
*
* @param int|string $eventsource
*/
function get_conditions_by_eventsource($eventsource): array {
$conditions[EVENT_SOURCE_TRIGGERS] = [
CONDITION_TYPE_TRIGGER_NAME,
CONDITION_TYPE_TRIGGER,
CONDITION_TYPE_TRIGGER_SEVERITY,
CONDITION_TYPE_HOST,
CONDITION_TYPE_HOST_GROUP,
CONDITION_TYPE_SUPPRESSED,
CONDITION_TYPE_EVENT_TAG,
CONDITION_TYPE_EVENT_TAG_VALUE,
CONDITION_TYPE_TEMPLATE,
CONDITION_TYPE_TIME_PERIOD
];
$conditions[EVENT_SOURCE_DISCOVERY] = [
CONDITION_TYPE_DHOST_IP,
CONDITION_TYPE_DCHECK,
CONDITION_TYPE_DOBJECT,
CONDITION_TYPE_DRULE,
CONDITION_TYPE_DSTATUS,
CONDITION_TYPE_PROXY,
CONDITION_TYPE_DVALUE,
CONDITION_TYPE_DSERVICE_PORT,
CONDITION_TYPE_DSERVICE_TYPE,
CONDITION_TYPE_DUPTIME
];
$conditions[EVENT_SOURCE_AUTOREGISTRATION] = [
CONDITION_TYPE_HOST_NAME,
CONDITION_TYPE_HOST_METADATA,
CONDITION_TYPE_PROXY
];
$conditions[EVENT_SOURCE_INTERNAL] = [
CONDITION_TYPE_EVENT_TYPE,
CONDITION_TYPE_HOST,
CONDITION_TYPE_HOST_GROUP,
CONDITION_TYPE_EVENT_TAG,
CONDITION_TYPE_EVENT_TAG_VALUE,
CONDITION_TYPE_TEMPLATE
];
$conditions[EVENT_SOURCE_SERVICE] = [
CONDITION_TYPE_SERVICE,
CONDITION_TYPE_SERVICE_NAME,
CONDITION_TYPE_EVENT_TAG,
CONDITION_TYPE_EVENT_TAG_VALUE
];
if (array_key_exists($eventsource, $conditions)) {
return $conditions[$eventsource];
}
return $conditions[EVENT_SOURCE_TRIGGERS];
}
/**
* Return allowed operations types.
*
* @param int $eventsource
*/
function getAllowedOperations($eventsource): array {
switch ($eventsource) {
case EVENT_SOURCE_TRIGGERS:
case EVENT_SOURCE_SERVICE:
return [
ACTION_OPERATION => [
OPERATION_TYPE_MESSAGE,
OPERATION_TYPE_COMMAND
],
ACTION_RECOVERY_OPERATION => [
OPERATION_TYPE_MESSAGE,
OPERATION_TYPE_COMMAND,
OPERATION_TYPE_RECOVERY_MESSAGE
],
ACTION_UPDATE_OPERATION => [
OPERATION_TYPE_MESSAGE,
OPERATION_TYPE_COMMAND,
OPERATION_TYPE_UPDATE_MESSAGE
]
];
case EVENT_SOURCE_DISCOVERY:
case EVENT_SOURCE_AUTOREGISTRATION:
return [
ACTION_OPERATION => [
OPERATION_TYPE_MESSAGE,
OPERATION_TYPE_COMMAND,
OPERATION_TYPE_HOST_ADD,
OPERATION_TYPE_HOST_REMOVE,
OPERATION_TYPE_GROUP_ADD,
OPERATION_TYPE_GROUP_REMOVE,
OPERATION_TYPE_TEMPLATE_ADD,
OPERATION_TYPE_TEMPLATE_REMOVE,
OPERATION_TYPE_HOST_TAGS_ADD,
OPERATION_TYPE_HOST_TAGS_REMOVE,
OPERATION_TYPE_HOST_ENABLE,
OPERATION_TYPE_HOST_DISABLE,
OPERATION_TYPE_HOST_INVENTORY
]
];
case EVENT_SOURCE_INTERNAL:
return [
ACTION_OPERATION => [OPERATION_TYPE_MESSAGE],
ACTION_RECOVERY_OPERATION => [
OPERATION_TYPE_MESSAGE,
OPERATION_TYPE_RECOVERY_MESSAGE
]
];
default:
return [];
}
}
/**
* Get operation type text label according $type value. If $type is equal null array of all available operation types
* will be returned.
*
* @param int|null $type Operation type, one of OPERATION_TYPE_* constant or null.
*
* @return string|array
*/
function operation_type2str($type) {
$types = [
OPERATION_TYPE_MESSAGE => _('Send message'),
OPERATION_TYPE_COMMAND => _('Remote command'),
OPERATION_TYPE_HOST_ADD => _('Add host'),
OPERATION_TYPE_HOST_REMOVE => _('Remove host'),
OPERATION_TYPE_HOST_ENABLE => _('Enable host'),
OPERATION_TYPE_HOST_DISABLE => _('Disable host'),
OPERATION_TYPE_GROUP_ADD => _('Add to host group'),
OPERATION_TYPE_GROUP_REMOVE => _('Remove from host group'),
OPERATION_TYPE_TEMPLATE_ADD => _('Link template'),
OPERATION_TYPE_TEMPLATE_REMOVE => _('Unlink template'),
OPERATION_TYPE_HOST_INVENTORY => _('Set host inventory mode'),
OPERATION_TYPE_RECOVERY_MESSAGE => _('Notify all involved'),
OPERATION_TYPE_UPDATE_MESSAGE => _('Notify all involved'),
OPERATION_TYPE_HOST_TAGS_ADD => _('Add host tags'),
OPERATION_TYPE_HOST_TAGS_REMOVE => _('Remove host tags')
];
if (is_null($type)) {
return order_result($types);
}
elseif (array_key_exists($type, $types)) {
return $types[$type];
}
else {
return _('Unknown');
}
}
function sortOperations($eventsource, &$operations): void {
if (in_array($eventsource, [EVENT_SOURCE_TRIGGERS, EVENT_SOURCE_INTERNAL, EVENT_SOURCE_SERVICE])) {
$esc_step_from = [];
$esc_step_to = [];
$esc_period = [];
$operationTypes = [];
$simple_interval_parser = new CSimpleIntervalParser();
foreach ($operations as $key => $operation) {
$esc_step_from[$key] = $operation['esc_step_from'];
$esc_step_to[$key] = $operation['esc_step_to'];
/*
* Try to sort by "esc_period" in seconds, otherwise sort as string in case it's a macro or something
* invalid.
*/
$esc_period[$key] = ($simple_interval_parser->parse($operation['esc_period']) == CParser::PARSE_SUCCESS)
? timeUnitToSeconds($operation['esc_period'])
: $operation['esc_period'];
$operationTypes[$key] = $operation['operationtype'];
}
array_multisort($esc_step_from, SORT_ASC, $esc_step_to, SORT_ASC, $esc_period, SORT_ASC, $operationTypes,
SORT_ASC, $operations
);
}
else {
$order = getAllowedOperations($eventsource)[ACTION_OPERATION];
usort($operations,
static fn($a, $b) => array_search($a['operationtype'], $order) - array_search($b['operationtype'], $order)
);
}
}
/**
* Return an array of operators supported by the given action condition.
*
* @param int $conditiontype
*/
function get_operators_by_conditiontype($conditiontype): array {
switch ($conditiontype) {
case CONDITION_TYPE_DCHECK:
case CONDITION_TYPE_DHOST_IP:
case CONDITION_TYPE_DRULE:
case CONDITION_TYPE_DSERVICE_PORT:
case CONDITION_TYPE_DSERVICE_TYPE:
case CONDITION_TYPE_HOST:
case CONDITION_TYPE_HOST_GROUP:
case CONDITION_TYPE_PROXY:
case CONDITION_TYPE_SERVICE:
case CONDITION_TYPE_TEMPLATE:
case CONDITION_TYPE_TRIGGER:
return [
CONDITION_OPERATOR_EQUAL,
CONDITION_OPERATOR_NOT_EQUAL
];
case CONDITION_TYPE_SERVICE_NAME:
case CONDITION_TYPE_TRIGGER_NAME:
return [
CONDITION_OPERATOR_LIKE,
CONDITION_OPERATOR_NOT_LIKE
];
case CONDITION_TYPE_TRIGGER_SEVERITY:
return [
CONDITION_OPERATOR_EQUAL,
CONDITION_OPERATOR_NOT_EQUAL,
CONDITION_OPERATOR_MORE_EQUAL,
CONDITION_OPERATOR_LESS_EQUAL
];
case CONDITION_TYPE_TIME_PERIOD:
return [
CONDITION_OPERATOR_IN,
CONDITION_OPERATOR_NOT_IN
];
case CONDITION_TYPE_SUPPRESSED:
return [
CONDITION_OPERATOR_NO,
CONDITION_OPERATOR_YES
];
case CONDITION_TYPE_DOBJECT:
case CONDITION_TYPE_DSTATUS:
case CONDITION_TYPE_EVENT_ACKNOWLEDGED:
case CONDITION_TYPE_EVENT_TYPE:
return [
CONDITION_OPERATOR_EQUAL
];
case CONDITION_TYPE_DUPTIME:
return [
CONDITION_OPERATOR_MORE_EQUAL,
CONDITION_OPERATOR_LESS_EQUAL
];
case CONDITION_TYPE_DVALUE:
return [
CONDITION_OPERATOR_EQUAL,
CONDITION_OPERATOR_NOT_EQUAL,
CONDITION_OPERATOR_MORE_EQUAL,
CONDITION_OPERATOR_LESS_EQUAL,
CONDITION_OPERATOR_LIKE,
CONDITION_OPERATOR_NOT_LIKE
];
case CONDITION_TYPE_HOST_METADATA:
case CONDITION_TYPE_HOST_NAME:
return [
CONDITION_OPERATOR_LIKE,
CONDITION_OPERATOR_NOT_LIKE,
CONDITION_OPERATOR_REGEXP,
CONDITION_OPERATOR_NOT_REGEXP
];
case CONDITION_TYPE_EVENT_TAG:
case CONDITION_TYPE_EVENT_TAG_VALUE:
return [
CONDITION_OPERATOR_EQUAL,
CONDITION_OPERATOR_NOT_EQUAL,
CONDITION_OPERATOR_LIKE,
CONDITION_OPERATOR_NOT_LIKE
];
default:
return [];
}
}
function count_operations_delay($operations, $def_period): array {
$delays = [1 => 0];
$periods = [];
$max_step = 0;
$simple_interval_parser = new CSimpleIntervalParser();
$def_period = CMacrosResolverHelper::resolveTimeUnitMacros(
[['def_period' => $def_period]], ['def_period']
)[0]['def_period'];
$def_period = ($simple_interval_parser->parse($def_period) == CParser::PARSE_SUCCESS)
? timeUnitToSeconds($def_period)
: null;
$operations = CMacrosResolverHelper::resolveTimeUnitMacros($operations, ['esc_period']);
foreach ($operations as $operation) {
$esc_period = ($simple_interval_parser->parse($operation['esc_period']) == CParser::PARSE_SUCCESS)
? timeUnitToSeconds($operation['esc_period'])
: null;
$esc_period = ($esc_period === null || $esc_period != 0) ? $esc_period : $def_period;
$step_to = ($operation['esc_step_to'] != 0) ? $operation['esc_step_to'] : 9999;
if ($max_step < $operation['esc_step_from']) {
$max_step = $operation['esc_step_from'];
}
for ($i = $operation['esc_step_from']; $i <= $step_to; $i++) {
if (!array_key_exists($i, $periods) || $esc_period === null || $periods[$i] > $esc_period) {
$periods[$i] = $esc_period;
}
}
}
for ($i = 1; $i <= $max_step; $i++) {
$esc_period = array_key_exists($i, $periods) ? $periods[$i] : $def_period;
$delays[$i + 1] = ($esc_period !== null && $delays[$i] !== null) ? $delays[$i] + $esc_period : null;
}
return $delays;
}
/**
* Returns the names of the "Event type" action condition values.
*
* If the $type parameter is passed, returns the name of the specific value, otherwise - returns an array of all
* supported values.
*
* @param string $type
*
* @return array|string
*/
function eventType($type = null) {
$types = [
EVENT_TYPE_ITEM_NOTSUPPORTED => _('Item in "not supported" state'),
EVENT_TYPE_LLDRULE_NOTSUPPORTED => _('Low-level discovery rule in "not supported" state'),
EVENT_TYPE_TRIGGER_UNKNOWN => _('Trigger in "unknown" state')
];
if (is_null($type)) {
return $types;
}
return $types[$type];
}
/**
* Get data required to create messages, severity changes, actions icon with popup with event actions.
*
* @param array $events Array with event objects with acknowledges.
* @param array $triggers Array of triggers.
*/
function getEventsActionsIconsData(array $events, array $triggers): array {
$suppressions = getEventsSuppressions($events);
$messages = getEventsMessages($events);
$severities = getEventsSeverityChanges($events, $triggers);
$actions = getEventsAlertsOverview($events);
return [
'data' => [
'suppressions' => $suppressions['data'],
'messages' => $messages['data'],
'severities' => $severities['data'],
'actions' => $actions
],
'userids' => $messages['userids'] + $severities['userids'] + $suppressions['userids']
];
}
/**
* Get data, required to create suppressed problem icon with popup with event suppression data.
*
* @param array $events Array with event objects with acknowledges.
* string $events[]['eventid'] Problem event ID.
* array $events[]['acknowledges'] Array with manual updates to problem.
* string $events[]['acknowledges'][]['action'] Action that was performed by problem update.
* string $events[]['acknowledges'][]['suppress_until'] Time until problem suppressed.
* string $events[]['acknowledges'][]['clock'] Time when manual suppression was made.
* string $events[]['acknowledges'][]['userid'] Author's userid.
*/
function getEventsSuppressions(array $events): array {
$suppressions = [];
$userids = [];
// Create array of suppressions for each event.
foreach ($events as $event) {
$event_suppressions = [];
foreach ($event['acknowledges'] as $ack) {
if (($ack['action'] & ZBX_PROBLEM_UPDATE_SUPPRESS) == ZBX_PROBLEM_UPDATE_SUPPRESS) {
$event_suppressions[] = [
'suppress_until' => $ack['suppress_until'],
'userid' => $ack['userid'],
'clock' => $ack['clock']
];
$userids[$ack['userid']] = true;
}
elseif (($ack['action'] & ZBX_PROBLEM_UPDATE_UNSUPPRESS) == ZBX_PROBLEM_UPDATE_UNSUPPRESS) {
$event_suppressions[] = [
'userid' => $ack['userid'],
'clock' => $ack['clock']
];
$userids[$ack['userid']] = true;
}
}
CArrayHelper::sort($event_suppressions, [['field' => 'clock', 'order' => ZBX_SORT_DOWN]]);
$suppressions[$event['eventid']] = [
'suppress_until' => array_values($event_suppressions),
'count' => count($event_suppressions)
];
}
return [
'data' => $suppressions,
'userids' => $userids
];
}
/**
* Get data, required to create messages icon with popup with event messages.
*
* @param array $events Array with event objects with acknowledges.
* string $events[]['eventid'] Problem event ID.
* array $events[]['acknowledges'] Array with manual updates to problem.
* string $events[]['acknowledges'][]['action'] Action that was performed by problem update.
* string $events[]['acknowledges'][]['message'] Message text.
* string $events[]['acknowledges'][]['clock'] Time when message was added.
* string $events[]['acknowledges'][]['userid'] Author's userid.
*/
function getEventsMessages(array $events): array {
$messages = [];
$userids = [];
// Create array of messages for each event
foreach ($events as $event) {
$event_messages = [];
foreach ($event['acknowledges'] as $ack) {
if (($ack['action'] & ZBX_PROBLEM_UPDATE_MESSAGE) == ZBX_PROBLEM_UPDATE_MESSAGE) {
$event_messages[] = [
'message' => $ack['message'],
'userid' => $ack['userid'],
'clock' => $ack['clock']
];
$userids[$ack['userid']] = true;
}
}
CArrayHelper::sort($event_messages, [['field' => 'clock', 'order' => ZBX_SORT_DOWN]]);
$messages[$event['eventid']] = [
'messages' => array_values($event_messages),
'count' => count($event_messages)
];
}
return [
'data' => $messages,
'userids' => $userids
];
}
/**
* Get data, required to create severity changes icon with popup with event severity changes.
*
* @param array $events Array with event objects with acknowledges.
* string $events[]['eventid'] Problem event ID.
* string $events[]['severity'] Current event severity.
* string $events[]['objectid'] Related trigger ID.
* array $events[]['acknowledges'] Array with manual updates to problem.
* string $events[]['acknowledges'][]['action'] Action that was performed by problem update.
* string $events[]['acknowledges'][]['clock'] Time when severity was changed.
* string $events[]['acknowledges'][]['old_severity'] Severity before the change.
* string $events[]['acknowledges'][]['new_severity'] Severity after the change.
* string $events[]['acknowledges'][]['userid'] Responsible user's userid.
* @param array $triggers Related trigger data.
* string $triggers[]['priority'] Severity of trigger.
*/
function getEventsSeverityChanges(array $events, array $triggers): array {
$severities = [];
$userids = [];
// Create array of messages for each event.
foreach ($events as $event) {
$event_severities = [];
foreach ($event['acknowledges'] as $ack) {
if (($ack['action'] & ZBX_PROBLEM_UPDATE_SEVERITY) == ZBX_PROBLEM_UPDATE_SEVERITY) {
$event_severities[] = [
'old_severity' => $ack['old_severity'],
'new_severity' => $ack['new_severity'],
'userid' => $ack['userid'],
'clock' => $ack['clock']
];
$userids[$ack['userid']] = true;
}
}
CArrayHelper::sort($event_severities, [['field' => 'clock', 'order' => ZBX_SORT_DOWN]]);
$severities[$event['eventid']] = [
'severities' => array_values($event_severities),
'count' => count($event_severities),
'original_severity' => $triggers[$event['objectid']]['priority'],
'current_severity' => $event['severity']
];
}
return [
'data' => $severities,
'userids' => $userids
];
}
/**
* Get data, required to create actions icon.
*
* @param array $events Array with event objects with acknowledges.
* string $events[]['eventid'] Problem event ID.
* string $events[]['r_eventid'] OK event ID.
*
* @return array List indexed by eventid containing overview on event alerts.
*/
function getEventsAlertsOverview(array $events): array {
$alert_eventids = [];
$actions = [];
$event_alert_state = [];
foreach ($events as $event) {
// Get alerts for event.
$alert_eventids[$event['eventid']] = true;
// Get alerts for related recovery events.
if ($event['r_eventid'] != 0) {
$alert_eventids[$event['r_eventid']] = true;
}
}
if ($alert_eventids) {
$event_alert_state = array_combine(array_keys($alert_eventids), array_fill(0, count($alert_eventids), [
'failed_cnt' => 0,
'in_progress_cnt' => 0,
'total_cnt' => 0
]));
$alerts = API::Alert()->get([
'groupCount' => true,
'countOutput' => true,
'filter' => ['status' => ALERT_STATUS_FAILED],
'eventids' => array_keys($alert_eventids)
]);
foreach ($alerts as $alert) {
$event_alert_state[$alert['eventid']]['failed_cnt'] = (int) $alert['rowscount'];
}
$alerts = API::Alert()->get([
'groupCount' => true,
'countOutput' => true,
'filter' => ['status' => [ALERT_STATUS_NEW, ALERT_STATUS_NOT_SENT]],
'eventids' => array_keys($alert_eventids)
]);
foreach ($alerts as $alert) {
$event_alert_state[$alert['eventid']]['in_progress_cnt'] = (int) $alert['rowscount'];
}
$alerts = API::Alert()->get([
'groupCount' => true,
'countOutput' => true,
'eventids' => array_keys($alert_eventids)
]);
foreach ($alerts as $alert) {
$event_alert_state[$alert['eventid']]['total_cnt'] = (int) $alert['rowscount'];
}
}
// Create array of actions for each event.
foreach ($events as $event) {
$event_actions = $event_alert_state[$event['eventid']];
if ($event['r_eventid']) {
$r_event_actions = $event_alert_state[$event['r_eventid']];
$event_actions['failed_cnt'] += $r_event_actions['failed_cnt'];
$event_actions['total_cnt'] += $r_event_actions['total_cnt'];
$event_actions['in_progress_cnt'] += $r_event_actions['in_progress_cnt'];
}
$actions[$event['eventid']] = [
'count' => $event_actions['total_cnt'] + count($event['acknowledges']),
'has_uncomplete_action' => (bool) $event_actions['in_progress_cnt'],
'has_failed_action' => (bool) $event_actions['failed_cnt']
];
}
return $actions;
}
/**
* Get data, required to create table with all (automatic and manual) actions for Event details page.
*
* @param array $event Event object with acknowledges.
* string $event['eventid'] Problem event ID.
* string $event['r_eventid'] OK event ID.
*/
function getEventDetailsActions(array $event): array {
$r_events = [];
// Select eventids for alert retrieval.
$alert_eventids = [$event['eventid']];
if ($event['r_eventid'] != 0) {
$alert_eventids[] = $event['r_eventid'];
$r_events = API::Event()->get([
'output' => ['clock'],
'eventids' => $event['r_eventid'],
'preservekeys' => true
]);
}
$search_limit = CSettingsHelper::get(CSettingsHelper::SEARCH_LIMIT);
// Get automatic actions (alerts).
$alerts = API::Alert()->get([
'output' => ['alerttype', 'clock', 'error', 'eventid', 'esc_step', 'mediatypeid', 'message', 'retries',
'sendto', 'status', 'subject', 'userid', 'p_eventid', 'acknowledgeid'
],
'eventids' => $alert_eventids,
'limit' => $search_limit
]);
$actions = getSingleEventActions($event, $r_events, $alerts);
return [
'actions' => $actions['actions'],
'mediatypeids' => $actions['mediatypeids'],
'userids' => $actions['userids'],
'count' => $actions['count']
];
}
/**
* Get array with all actions for single event.
*
* @param array $event Event objects with acknowledges.
* string $event['eventid'] Problem event ID.
* string $event['r_eventid'] OK event ID.
* string $event['clock'] Time when event occurred.
* array $event['acknowledges'] Array with manual updates to problem.
* string $event['acknowledges'][]['userid'] User ID.
* @param array $r_events Recovery event data for all requested events.
* string $r_events[]['clock'] Recovery event creation time.
* @param array $alerts Alert data for all requested alerts.
* string $alerts[]['eventid'] If of problem event for which this alert was generated.
* string $alerts[]['mediatypeid'] ID for mediatype used for alert.
* string $alerts[]['alerttype'] Type of alert.
* string $alerts[]['status'] Alert status.
* string $alerts[]['userid'] ID of alert recipient.
*/
function getSingleEventActions(array $event, array $r_events, array $alerts): array {
$action_count = 0;
$has_uncomplete_action = false;
$has_failed_action = false;
$mediatypeids = [];
$userids = [];
// Create array of automatically and manually performed actions combined.
$actions = [];
// Add row for problem generation event.
$actions[] = [
'action_type' => ZBX_EVENT_HISTORY_PROBLEM_EVENT,
'clock' => $event['clock']
];
// Add row for problem recovery event.
if (array_key_exists($event['r_eventid'], $r_events)) {
$actions[] = [
'action_type' => ZBX_EVENT_HISTORY_RECOVERY_EVENT,
'clock' => $r_events[$event['r_eventid']]['clock']
];
}
// Add manual operations.
foreach ($event['acknowledges'] as $ack) {
$ack['action_type'] = ZBX_EVENT_HISTORY_MANUAL_UPDATE;
$actions[] = $ack;
$action_count++;
$userids[$ack['userid']] = true;
}
// Add alerts.
foreach ($alerts as $alert) {
// Add only alerts, related to current event.
if (bccomp($alert['eventid'], $event['eventid']) == 0
|| bccomp($alert['eventid'], $event['r_eventid']) == 0) {
$alert['action_type'] = ZBX_EVENT_HISTORY_ALERT;
$actions[] = $alert;
$action_count++;
if ($alert['alerttype'] == ALERT_TYPE_MESSAGE) {
if ($alert['mediatypeid'] != 0) {
$mediatypeids[$alert['mediatypeid']] = true;
}
if ($alert['userid'] != 0) {
$userids[$alert['userid']] = true;
}
}
if ($alert['status'] == ALERT_STATUS_NEW || $alert['status'] == ALERT_STATUS_NOT_SENT) {
$has_uncomplete_action = true;
}
elseif ($alert['status'] == ALERT_STATUS_FAILED) {
$has_failed_action = true;
}
}
}
// Sort by action_type is done to put Recovery event before actions, resulted from it. Same for other action_type.
CArrayHelper::sort($actions, [
['field' => 'clock', 'order' => ZBX_SORT_DOWN],
['field' => 'action_type', 'order' => ZBX_SORT_DOWN],
['field' => 'alertid', 'order' => ZBX_SORT_DOWN]
]);
return [
'actions' => array_values($actions),
'count' => $action_count,
'has_uncomplete_action' => $has_uncomplete_action,
'has_failed_action' => $has_failed_action,
'mediatypeids' => $mediatypeids,
'userids' => $userids
];
}
/**
* Get data required to create history list in problem update page.
*
* @param array $event Array with event objects with acknowledges.
* array $event['acknowledges'] Array with manual updates to problem.
* string $event['acknowledges'][]['clock'] Time when severity was changed.
* string $event['acknowledges'][]['userid'] Responsible user's userid.
*/
function getEventUpdates(array $event): array {
$userids = [];
foreach ($event['acknowledges'] as $ack) {
$userids[$ack['userid']] = true;
}
CArrayHelper::sort($event['acknowledges'], [['field' => 'clock', 'order' => ZBX_SORT_DOWN]]);
return [
'data' => array_values($event['acknowledges']),
'userids' => $userids
];
}
/**
* Make icons (suppressions, messages, severity changes, actions) for actions column.
*
* @param string $eventid ID for event, for which icons are created.
* @param array $actions Array of actions data.
* array $actions['suppressions'] Suppression icon data.
* array $actions['messages'] Messages icon data.
* array $actions['severities'] Severity change icon data.
* array $actions['actions'] Actions icon data.
* @param array $users User name, surname and username.
* @param bool $is_acknowledged Is the event currently acknowledged. If true, display icon.
*
* @throws Exception
*
* @return CCol|string
*/
function makeEventActionsIcons($eventid, array $actions, array $users, bool $is_acknowledged) {
$suppression_icon = makeEventSuppressionsProblemIcon($actions['suppressions'][$eventid], $users);
$messages_icon = makeEventMessagesIcon($actions['messages'][$eventid], $users);
$severities_icon = makeEventSeverityChangesIcon($actions['severities'][$eventid], $users);
$actions_icon = makeEventActionsIcon($actions['actions'][$eventid], $eventid);
$action_icons = [];
if ($is_acknowledged) {
$action_icons[] = (new CIcon(ZBX_ICON_CHECK, _('Acknowledged')))->addClass(ZBX_STYLE_COLOR_POSITIVE);
}
if ($suppression_icon !== null) {
$action_icons[] = $suppression_icon;
}
if ($messages_icon !== null) {
$action_icons[] = $messages_icon;
}
if ($severities_icon !== null) {
$action_icons[] = $severities_icon;
}
if ($actions_icon !== null) {
$action_icons[] = $actions_icon;
}
return $action_icons ? (new CCol($action_icons))->addClass(ZBX_STYLE_NOWRAP) : '';
}
/**
* Create icon with hintbox for event suppressions.
* Records must be passed in the order starting from the latest by field 'clock'.
*
* @param array $data
* array $data['suppress_until'][]['suppress_until'] Time until problem is suppressed by user.
* string $data['suppress_until'][]['clock'] Suppression creation time.
* @param array $users User name, surname and username.
*
* @throws Exception
*/
function makeEventSuppressionsProblemIcon(array $data, array $users): ?CButtonIcon {
if ($data['count'] == 0) {
return null;
}
$table = (new CTableInfo())->setHeader([_('Time'), _('User'), _('Action'), _('Suppress until')]);
for ($i = 0; $i < $data['count'] && $i < ZBX_WIDGET_ROWS; $i++) {
$suppression = $data['suppress_until'][$i];
// Added in order to reuse makeActionTableUser().
$suppression['action_type'] = ZBX_EVENT_HISTORY_MANUAL_UPDATE;
if (array_key_exists('suppress_until', $suppression)) {
$icon = new CIcon(ZBX_ICON_EYE_OFF, _('Suppressed'));
if ($suppression['suppress_until'] == ZBX_PROBLEM_SUPPRESS_TIME_INDEFINITE) {
$suppress_until = _s('Indefinitely');
}
else {
$suppress_until = $suppression['suppress_until'] < strtotime('tomorrow')
&& $suppression['suppress_until'] > strtotime('today')
? zbx_date2str(TIME_FORMAT, $suppression['suppress_until'])
: zbx_date2str(DATE_TIME_FORMAT, $suppression['suppress_until']);
}
}
else {
$icon = new CIcon(ZBX_ICON_EYE, _('Unsuppressed'));
$suppress_until = '';
}
$table->addRow([
zbx_date2str(DATE_TIME_FORMAT_SECONDS, $suppression['clock']),
makeActionTableUser($suppression, $users),
$icon,
$suppress_until
]);
}
if ($data['count'] > ZBX_WIDGET_ROWS) {
$table->setFooter(
(new CCol(_s('Displaying %1$s of %2$s found', ZBX_WIDGET_ROWS, $data['count'])))
->addClass(ZBX_STYLE_LIST_TABLE_FOOTER)
);
}
return (new CButtonIcon(array_key_exists('suppress_until', $data['suppress_until'][0])
? ZBX_ICON_EYE_OFF
: ZBX_ICON_EYE
))
->addClass(ZBX_STYLE_COLOR_ICON)
->setHint($table, ZBX_STYLE_HINTBOX_WRAP_HORIZONTAL);
}
/**
* Create icon with hintbox for event messages.
*
* @param array $data
* int $data['count'] Number of messages.
* array $data['messages'] Array of messages.
* string $data['messages'][]['message'] Message text.
* string $data['messages'][]['clock'] Message creation time.
* @param array $users User name, surname and username.
*
* @throws Exception
*/
function makeEventMessagesIcon(array $data, array $users): ?CButtonIcon {
if ($data['count'] == 0) {
return null;
}
$table = (new CTableInfo())->setHeader([_('Time'), _('User'), _('Message')]);
for ($i = 0; $i < $data['count'] && $i < ZBX_WIDGET_ROWS; $i++) {
$message = $data['messages'][$i];
// Added in order to reuse makeActionTableUser().
$message['action_type'] = ZBX_EVENT_HISTORY_MANUAL_UPDATE;
$table->addRow([
zbx_date2str(DATE_TIME_FORMAT_SECONDS, $message['clock']),
makeActionTableUser($message, $users),
zbx_nl2br($message['message'])
]);
}
if ($data['count'] > ZBX_WIDGET_ROWS) {
$table->setFooter(
(new CCol(_s('Displaying %1$s of %2$s found', ZBX_WIDGET_ROWS, $data['count'])))
->addClass(ZBX_STYLE_LIST_TABLE_FOOTER)
);
}
return (new CButtonIcon(ZBX_ICON_ALERT_WITH_CONTENT))
->setAttribute('data-content', $data['count'])
->setAttribute('aria-label',
_xn('%1$s message', '%1$s messages', $data['count'], 'screen reader', $data['count'])
)
->setHint($table, ZBX_STYLE_HINTBOX_WRAP_HORIZONTAL);
}
/**
* Create icon with hintbox for event severity changes.
*
* @param array $data
* int $data['count'] Total number of severity changes.
* array $data['severities'] Array of severities.
* string $data['severities'][]['old_severity'] Event severity before change.
* string $data['severities'][]['new_severity'] Event severity after change.
* string $data['severities'][]['clock'] Severity change time.
* string $data['original_severity'] Severity before change.
* string $data['current_severity'] Current severity.
* @param array $users User name, surname and username.
*
* @throws Exception
*/
function makeEventSeverityChangesIcon(array $data, array $users): ?CButtonIcon {
if ($data['count'] == 0) {
return null;
}
$table = (new CTableInfo())->setHeader([_('Time'), _('User'), _('Severity changes')]);
for ($i = 0; $i < $data['count'] && $i < ZBX_WIDGET_ROWS; $i++) {
$severity = $data['severities'][$i];
// Added in order to reuse makeActionTableUser().
$severity['action_type'] = ZBX_EVENT_HISTORY_MANUAL_UPDATE;
// severity changes
$old_severity_name = CSeverityHelper::getName((int) $severity['old_severity']);
$new_severity_name = CSeverityHelper::getName((int) $severity['new_severity']);
$table->addRow([
zbx_date2str(DATE_TIME_FORMAT_SECONDS, $severity['clock']),
makeActionTableUser($severity, $users),
[$old_severity_name, NBSP(), RARR(), NBSP(), $new_severity_name]
]);
}
if ($data['count'] > ZBX_WIDGET_ROWS) {
$table->setFooter(
(new CCol(_s('Displaying %1$s of %2$s found', ZBX_WIDGET_ROWS, $data['count'])))
->addClass(ZBX_STYLE_LIST_TABLE_FOOTER)
);
}
if ($data['original_severity'] > $data['current_severity']) {
$button = (new CButtonIcon(ZBX_ICON_ARROW_DOWN_SMALL))
->addClass(ZBX_STYLE_COLOR_POSITIVE)
->setAttribute('aria-label', _x('Severity decreased', 'screen reader'));
}
elseif ($data['original_severity'] < $data['current_severity']) {
$button = (new CButtonIcon(ZBX_ICON_ARROW_UP_SMALL))
->addClass(ZBX_STYLE_COLOR_NEGATIVE)
->setAttribute('aria-label', _x('Severity increased', 'screen reader'));
}
else {
$button = (new CButtonIcon(ZBX_ICON_ARROWS_TOP_BOTTOM))
->addClass(ZBX_STYLE_COLOR_ICON)
->setAttribute('aria-label', _x('Severity changed', 'screen reader'));
}
return $button->setHint($table, ZBX_STYLE_HINTBOX_WRAP_HORIZONTAL);
}
/**
* @param array $actions Array with all actions sorted by clock.
* int $actions[]['action_type'] Type of action table entry (ZBX_EVENT_HISTORY_*).
* string $actions[]['clock'] Time, when action was performed.
* string $actions[]['message'] Message sent by alert, or written by manual update, or remote command text.
* string $actions[]['action'] Flag with problem update operation performed (only for ZBX_EVENT_HISTORY_MANUAL_UPDATE).
* string $actions[]['alerttype'] Type of alert (only for ZBX_EVENT_HISTORY_ALERT).
* string $actions[]['mediatypeid'] Id for mediatype, where alert message was sent (only for ZBX_EVENT_HISTORY_ALERT).
* string $actions[]['error'] Error message in case of failed alert (only for ZBX_EVENT_HISTORY_ALERT).
* @param array $users User name, surname and username.
* @param array $mediatypes Mediatypes with maxattempts value and name.
* string $mediatypes[]['name'] Mediatype name.
* string $mediatypes[]['maxattempts'] Maximum attempts for this mediatype.
*
* @throws Exception
*/
function makeEventActionsTable(array $actions, array $users, array $mediatypes): CTableInfo {
$action_count = count($actions);
$table = (new CTableInfo())->setHeader([
_('Time'), _('User/Recipient'), _('Action'), _('Message/Command'), _('Status'), _('Info')
]);
for ($i = 0; $i < $action_count && $i < ZBX_WIDGET_ROWS; $i++) {
$action = $actions[$i];
$message = '';
if ($action['action_type'] == ZBX_EVENT_HISTORY_MANUAL_UPDATE
&& ($action['action'] & ZBX_PROBLEM_UPDATE_MESSAGE) == ZBX_PROBLEM_UPDATE_MESSAGE) {
$message = zbx_nl2br($action['message']);
}
elseif ($action['action_type'] == ZBX_EVENT_HISTORY_ALERT) {
if ($action['alerttype'] == ALERT_TYPE_COMMAND) {
$message = _('Remote command');
}
elseif ($action['alerttype'] == ALERT_TYPE_MESSAGE) {
$message = array_key_exists($action['mediatypeid'], $mediatypes)
? $mediatypes[$action['mediatypeid']]['name']
: '';
}
}
$table->addRow([
zbx_date2str(DATE_TIME_FORMAT_SECONDS, $action['clock']),
makeActionTableUser($action, $users),
makeActionTableIcon($action),
$message,
makeActionTableStatus($action),
makeActionTableInfo($action, $mediatypes)
]);
}
return $table;
}
/**
* Create icon with hintbox for event actions.
*
* @param array $data
* int $data['count'] Number of actions.
* bool $data['has_uncomplete_action'] Does the event have at least one uncompleted alert action.
* bool $data['has_failed_action'] Does the event have at least one failed alert action.
* @param string $eventid
*/
function makeEventActionsIcon(array $data, $eventid): ?CButtonIcon {
if ($data['count'] == 0) {
return null;
}
$button = new CButtonIcon(ZBX_ICON_BULLET_RIGHT_WITH_CONTENT);
if ($data['has_failed_action']) {
$button->addClass(ZBX_STYLE_COLOR_NEGATIVE);
}
elseif ($data['has_uncomplete_action']) {
$button->addClass(ZBX_STYLE_COLOR_WARNING);
}
return $button
->setAttribute('data-content', $data['count'])
->setAttribute('aria-label',
_xn('%1$s action', '%1$s actions', $data['count'], 'screen reader', $data['count'])
)
->setAjaxHint([
'type' => 'eventactions',
'data' => ['eventid' => $eventid]
], ZBX_STYLE_HINTBOX_WRAP_HORIZONTAL);
}
/**
* Get table with list of event actions for event details page.
*
* @param array $data
* array $data['actions'] Array with all actions sorted by clock.
* int $data['actions'][]['action_type'] Type of action table entry (ZBX_EVENT_HISTORY_*).
* string $data['actions'][]['clock'] Time, when action was performed.
* string $data['actions'][]['message'] Message sent by alert, or written by manual update, or remote command text.
* string $data['actions'][]['alerttype'] Type of alert (only for ZBX_EVENT_HISTORY_ALERT).
* string $data['actions'][]['esc_step'] Alert escalation step (only for ZBX_EVENT_HISTORY_ALERT).
* string $data['actions'][]['subject'] Message alert subject (only for ZBX_EVENT_HISTORY_ALERT).
* string $data['actions'][]['p_eventid'] Problem eventid that was reason for alert (only for ZBX_EVENT_HISTORY_ALERT).
* string $data['actions'][]['acknowledgeid'] Problem update action that was reason for alert (only for ZBX_EVENT_HISTORY_ALERT).
* @param array $users User name, surname and username.
* @param array $mediatypes Mediatypes with maxattempts value.
*/
function makeEventDetailsActionsTable(array $data, array $users, array $mediatypes): CTableInfo {
$table = (new CTableInfo())->setHeader([
_('Step'), _('Time'), _('User/Recipient'), _('Action'), _('Message/Command'), _('Status'), _('Info')
]);
foreach ($data['actions'] as $action) {
$esc_step = '';
if ($action['action_type'] == ZBX_EVENT_HISTORY_ALERT && $action['p_eventid'] == 0
&& $action['acknowledgeid'] == 0) {
/*
* Escalation step should be displayed, only if alert is caused by problem event.
* Escalation step should not be displayed, if alert is caused by resolve event, or by problem update.
*/
$esc_step = $action['esc_step'];
}
$message = '';
switch ($action['action_type']) {
case ZBX_EVENT_HISTORY_ALERT:
switch ($action['alerttype']) {
case ALERT_TYPE_MESSAGE:
$message = [bold($action['subject']), BR(), BR(), zbx_nl2br($action['message'])];
break;
case ALERT_TYPE_COMMAND:
$message = [bold(_('Command').':'), BR(), zbx_nl2br($action['message'])];
break;
}
break;
case ZBX_EVENT_HISTORY_MANUAL_UPDATE:
$message = zbx_nl2br($action['message']);
break;
}
$table->addRow([
$esc_step,
zbx_date2str(DATE_TIME_FORMAT_SECONDS, $action['clock']),
makeEventDetailsTableUser($action, $users),
makeActionTableIcon($action),
$message,
makeActionTableStatus($action),
makeActionTableInfo($action, $mediatypes)
]);
}
return $table;
}
/**
* Get table with list of event updates for update event page.
*
* @param array $actions Array with all actions sorted by clock.
* string $actions[]['clock'] Time, when action was performed.
* string $actions[]['message'] Message sent by alert, or written by manual update, or remote command text.
* @param array $users User name, surname and username.
*/
function makeEventHistoryTable(array $actions, array $users): CTable {
$table = (new CTable())
->addStyle('width: 100%;')
->setHeader([_('Time'), _('User'), _('User action'), _('Message')]);
foreach ($actions as $action) {
// Added in order to reuse makeActionTableUser() and makeActionTableIcon()
$action['action_type'] = ZBX_EVENT_HISTORY_MANUAL_UPDATE;
$table->addRow([
zbx_date2str(DATE_TIME_FORMAT_SECONDS, $action['clock']),
makeActionTableUser($action, $users),
makeActionTableIcon($action),
(new CCol(zbx_nl2br($action['message'])))->addClass(ZBX_STYLE_TABLE_FORMS_OVERFLOW_BREAK)
]);
}
return $table;
}
/**
* Creates username for message author or alert receiver.
*
* @param array $action Array of action data.
* int $action['action_type'] Type of event table action (ZBX_EVENT_HISTORY_*).
* string $action['alerttype'] Type of alert.
* string $action['userid'] ID of message author, or alert receiver.
* @param array $users Array with user data - username, name, surname.
*/
function makeActionTableUser(array $action, array $users): string {
if (($action['action_type'] == ZBX_EVENT_HISTORY_ALERT && $action['alerttype'] == ALERT_TYPE_MESSAGE)
|| $action['action_type'] == ZBX_EVENT_HISTORY_MANUAL_UPDATE) {
return array_key_exists($action['userid'], $users)
? getUserFullname($users[$action['userid']])
: _('Inaccessible user');
}
else {
return '';
}
}
/**
* Creates username for message author or alert receiver. Also contains 'sendto' for message actions.
*
* @param array $action
* int $action['action_type'] Type of event table action (ZBX_EVENT_HISTORY_*).
* string $action['alerttype'] Type of alert.
* array $action['userid'] ID of message author, or alert receiver.
* array $action['sendto'] Receiver media address for automatic action.
* @param array $users Array with user data - username, name, surname.
*
* @return array|string
*/
function makeEventDetailsTableUser(array $action, array $users) {
if ($action['action_type'] == ZBX_EVENT_HISTORY_ALERT && $action['alerttype'] == ALERT_TYPE_MESSAGE) {
return array_key_exists($action['userid'], $users)
? [getUserFullname($users[$action['userid']]), BR(), italic(zbx_nl2br($action['sendto']))]
: _('Inaccessible user');
}
elseif ($action['action_type'] == ZBX_EVENT_HISTORY_MANUAL_UPDATE) {
return array_key_exists($action['userid'], $users)
? getUserFullname($users[$action['userid']])
: _('Inaccessible user');
}
else {
return '';
}
}
/**
* Make appropriate icon for event action.
*
* @param array $action Array with actions table data.
* int $action['action_type'] Type of action table entry (ZBX_EVENT_HISTORY_*).
* int $action['action'] Flag with problem update operation performed (only for ZBX_EVENT_HISTORY_MANUAL_UPDATE).
* int $action['old_severity'] Severity before problem update (only for ZBX_EVENT_HISTORY_MANUAL_UPDATE).
* int $action['new_severity'] Severity after problem update (only for ZBX_EVENT_HISTORY_MANUAL_UPDATE).
* int $action['alerttype'] Type of alert (only for ZBX_EVENT_HISTORY_ALERT).
*/
function makeActionTableIcon(array $action): ?CTag {
switch ($action['action_type']) {
case ZBX_EVENT_HISTORY_PROBLEM_EVENT:
return new CIcon(ZBX_ICON_CALENDAR_WARNING, _('Problem created'));
case ZBX_EVENT_HISTORY_RECOVERY_EVENT:
return new CIcon(ZBX_ICON_CALENDAR_CHECK, _('Problem resolved'));
case ZBX_EVENT_HISTORY_MANUAL_UPDATE:
$action_icons = [];
if (($action['action'] & ZBX_PROBLEM_UPDATE_CLOSE) == ZBX_PROBLEM_UPDATE_CLOSE) {
$action_icons[] = new CIcon(ZBX_ICON_CHECKBOX, _('Manually closed'));
}
if (($action['action'] & ZBX_PROBLEM_UPDATE_RANK_TO_CAUSE) == ZBX_PROBLEM_UPDATE_RANK_TO_CAUSE) {
$action_icons[] = new CIcon(ZBX_ICON_ARROW_RIGHT_TOP, _('Cause'));
}
if (($action['action'] & ZBX_PROBLEM_UPDATE_RANK_TO_SYMPTOM) == ZBX_PROBLEM_UPDATE_RANK_TO_SYMPTOM) {
$action_icons[] = new CIcon(ZBX_ICON_ARROW_TOP_RIGHT, _('Symptom'));
}
if (($action['action'] & ZBX_PROBLEM_UPDATE_ACKNOWLEDGE) == ZBX_PROBLEM_UPDATE_ACKNOWLEDGE) {
$action_icons[] = new CIcon(ZBX_ICON_CHECK, _('Acknowledged'));
}
if (($action['action'] & ZBX_PROBLEM_UPDATE_UNACKNOWLEDGE) == ZBX_PROBLEM_UPDATE_UNACKNOWLEDGE) {
$action_icons[] = new CIcon(ZBX_ICON_UNCHECK, _('Unacknowledged'));
}
if (($action['action'] & ZBX_PROBLEM_UPDATE_SUPPRESS) == ZBX_PROBLEM_UPDATE_SUPPRESS) {
if ($action['suppress_until'] == ZBX_PROBLEM_SUPPRESS_TIME_INDEFINITE) {
$suppress_until = _s('Indefinitely');
}
else {
$suppress_until = $action['suppress_until'] < strtotime('tomorrow')
&& $action['suppress_until'] > strtotime('today')
? zbx_date2str(TIME_FORMAT, $action['suppress_until'])
: zbx_date2str(DATE_TIME_FORMAT, $action['suppress_until']);
}
$action_icons[] = (new CButtonIcon(ZBX_ICON_EYE_OFF))
->addClass(ZBX_STYLE_COLOR_ICON)
->setHint(_s('Suppressed till: %1$s', $suppress_until), ZBX_STYLE_HINTBOX_WRAP_HORIZONTAL);
}
if (($action['action'] & ZBX_PROBLEM_UPDATE_UNSUPPRESS) == ZBX_PROBLEM_UPDATE_UNSUPPRESS) {
$action_icons[] = new CIcon(ZBX_ICON_EYE, _('Unsuppressed'));
}
if (($action['action'] & ZBX_PROBLEM_UPDATE_MESSAGE) == ZBX_PROBLEM_UPDATE_MESSAGE) {
$action_icons[] = new CIcon(ZBX_ICON_ALERT_MORE, _('Message'));
}
if (($action['action'] & ZBX_PROBLEM_UPDATE_SEVERITY) == ZBX_PROBLEM_UPDATE_SEVERITY) {
$button = $action['new_severity'] > $action['old_severity']
? (new CButtonIcon(ZBX_ICON_ARROW_UP_SMALL))->addClass(ZBX_STYLE_COLOR_NEGATIVE)
: (new CButtonIcon(ZBX_ICON_ARROW_DOWN_SMALL))->addClass(ZBX_STYLE_COLOR_POSITIVE);
$old_severity_name = CSeverityHelper::getName((int) $action['old_severity']);
$new_severity_name = CSeverityHelper::getName((int) $action['new_severity']);
$action_icons[] = $button->setHint(
[$old_severity_name, NBSP(), RARR(), NBSP(), $new_severity_name], ZBX_STYLE_HINTBOX_WRAP_HORIZONTAL
);
}
return (new CCol($action_icons))->addClass(ZBX_STYLE_NOWRAP);
case ZBX_EVENT_HISTORY_ALERT:
return $action['alerttype'] == ALERT_TYPE_COMMAND
? new CIcon(ZBX_ICON_COMMAND, _('Remote command'))
: new CIcon(ZBX_ICON_ENVELOPE_FILLED, _('Alert message'));
default:
return null;
}
}
/**
* Creates span with alert status text.
*
* @param array $action
* int $action['action_type'] Type of event table action (ZBX_EVENT_HISTORY_*).
* string $action['status'] Alert status.
* string $action['alerttype'] Type of alert.
*
* @return CSpan|string
*/
function makeActionTableStatus(array $action) {
if ($action['action_type'] != ZBX_EVENT_HISTORY_ALERT) {
return '';
}
switch ($action['status']) {
case ALERT_STATUS_SENT:
$status_label = ($action['alerttype'] == ALERT_TYPE_COMMAND)
? _('Executed')
: _('Sent');
$status_color = ZBX_STYLE_GREEN;
break;
case ALERT_STATUS_NEW:
case ALERT_STATUS_NOT_SENT:
$status_label = _('In progress');
$status_color = ZBX_STYLE_YELLOW;
break;
default:
$status_label = _('Failed');
$status_color = ZBX_STYLE_RED;
break;
}
return (new CSpan($status_label))->addClass($status_color);
}
/**
* Creates div with alert info icons.
*
* @param array $action
* int $action['action_type'] Type of event table action (ZBX_EVENT_HISTORY_*).
* string $action['status'] Alert status.
* string $action['alerttype'] Type of alert.
* string $action['mediatypeid'] ID for mediatype, where alert message was sent.
* string $action['retries'] How many retries were done for pending alert message.
* @param array $mediatypes Array of media type data.
* array $mediatypes[]['maxattempts'] Maximum attempts for this mediatype.
*
* @return CDiv|string
*/
function makeActionTableInfo(array $action, array $mediatypes) {
if ($action['action_type'] == ZBX_EVENT_HISTORY_ALERT) {
$info_icons = [];
if ($action['alerttype'] == ALERT_TYPE_MESSAGE
&& ($action['status'] == ALERT_STATUS_NEW || $action['status'] == ALERT_STATUS_NOT_SENT)) {
$info_icons[] = makeWarningIcon(array_key_exists($action['mediatypeid'], $mediatypes)
? _n('%1$s retry left', '%1$s retries left',
$mediatypes[$action['mediatypeid']]['maxattempts'] - $action['retries']
)
: ''
);
}
elseif ($action['error'] !== '') {
$info_icons[] = makeErrorIcon($action['error']);
}
return makeInformationList($info_icons);
}
else {
return '';
}
}