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.
693 lines
22 KiB
693 lines
22 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.
|
|
**/
|
|
|
|
|
|
/**
|
|
* Class containing methods for operations with tasks.
|
|
*/
|
|
class CTask extends CApiService {
|
|
|
|
public const ACCESS_RULES = [
|
|
'get' => ['min_user_type' => USER_TYPE_SUPER_ADMIN],
|
|
'create' => ['min_user_type' => USER_TYPE_SUPER_ADMIN]
|
|
];
|
|
|
|
protected $tableName = 'task';
|
|
protected $tableAlias = 't';
|
|
protected $sortColumns = ['taskid'];
|
|
|
|
private $item_cache = [];
|
|
|
|
const RESULT_STATUS_ERROR = -1;
|
|
|
|
/**
|
|
* Get results of requested ZBX_TM_TASK_DATA task.
|
|
*
|
|
* @param array $options
|
|
* @param string|array $options['output']
|
|
* @param string|array $options['taskids'] Task IDs to select data about.
|
|
* @param bool $options['preservekeys'] Use IDs as keys in the resulting array.
|
|
*
|
|
* @return array | boolean
|
|
*/
|
|
public function get(array $options): array {
|
|
if (self::$userData['type'] != USER_TYPE_SUPER_ADMIN) {
|
|
self::exception(ZBX_API_ERROR_PERMISSIONS, _('You do not have permission to perform this operation.'));
|
|
}
|
|
|
|
$output_fields = ['taskid', 'type', 'status', 'clock', 'ttl', 'proxyid', 'request', 'result'];
|
|
|
|
$api_input_rules = ['type' => API_OBJECT, 'fields' => [
|
|
// filter
|
|
'taskids' => ['type' => API_IDS, 'flags' => API_NORMALIZE | API_ALLOW_NULL, 'default' => null],
|
|
// output
|
|
'output' => ['type' => API_OUTPUT, 'in' => implode(',', $output_fields), 'default' => API_OUTPUT_EXTEND],
|
|
// flags
|
|
'preservekeys' => ['type' => API_BOOLEAN, 'default' => false]
|
|
]];
|
|
|
|
if (!CApiInputValidator::validate($api_input_rules, $options, '/', $error)) {
|
|
self::exception(ZBX_API_ERROR_PARAMETERS, $error);
|
|
}
|
|
|
|
$options += [
|
|
'sortfield' => 'taskid',
|
|
'sortorder' => ZBX_SORT_DOWN,
|
|
'limit' => CSettingsHelper::get(CSettingsHelper::SEARCH_LIMIT)
|
|
];
|
|
|
|
$sql_parts = [
|
|
'select' => ['task' => 't.taskid'],
|
|
'from' => ['task' => 'task t'],
|
|
'where' => [
|
|
'type' => 't.type='.ZBX_TM_TASK_DATA
|
|
],
|
|
'order' => [],
|
|
'group' => []
|
|
];
|
|
|
|
if ($options['taskids'] !== null) {
|
|
$sql_parts['where']['taskid'] = dbConditionInt('t.taskid', $options['taskids']);
|
|
}
|
|
|
|
$db_tasks = [];
|
|
|
|
$sql_parts = $this->applyQueryOutputOptions($this->tableName(), $this->tableAlias(), $options, $sql_parts);
|
|
$sql_parts = $this->applyQuerySortOptions($this->tableName(), $this->tableAlias(), $options, $sql_parts);
|
|
|
|
$result = DBselect($this->createSelectQueryFromParts($sql_parts), $options['limit']);
|
|
|
|
while ($row = DBfetch($result, false)) {
|
|
if ($this->outputIsRequested('request', $options['output'])) {
|
|
$row['request'] = json_decode($row['request_data']);
|
|
unset($row['request_data']);
|
|
}
|
|
|
|
if ($this->outputIsRequested('result', $options['output'])) {
|
|
if ($row['result_status'] === null) {
|
|
$row['result'] = null;
|
|
}
|
|
else {
|
|
if ($row['result_status'] == self::RESULT_STATUS_ERROR) {
|
|
$result_data = $row['result_info'];
|
|
}
|
|
else {
|
|
$result_data = $row['result_info'] ? json_decode($row['result_info']) : [];
|
|
}
|
|
|
|
$row['result'] = [
|
|
'data' => $result_data,
|
|
'status' => $row['result_status']
|
|
];
|
|
}
|
|
|
|
unset($row['result_info'], $row['result_status']);
|
|
}
|
|
|
|
$db_tasks[$row['taskid']] = $row;
|
|
}
|
|
|
|
if ($db_tasks) {
|
|
$db_tasks = $this->unsetExtraFields($db_tasks, ['taskid'], $options['output']);
|
|
|
|
if (!$options['preservekeys']) {
|
|
$db_tasks = array_values($db_tasks);
|
|
}
|
|
}
|
|
|
|
return $db_tasks;
|
|
}
|
|
|
|
/**
|
|
* Create tasks.
|
|
*
|
|
* @param array $tasks Tasks to create.
|
|
* @param string|array $tasks[]['type'] Type of task.
|
|
* @param string $tasks[]['request']['itemid'] Must be set for ZBX_TM_TASK_CHECK_NOW task.
|
|
* @param array $tasks[]['request']['historycache'] (optional) object of history cache data request.
|
|
* @param array $tasks[]['request']['valuecache'] (optional) object of value cache data request.
|
|
* @param array $tasks[]['request']['preprocessing'] (optional) object of preprocessing data request.
|
|
* @param array $tasks[]['request']['alerting'] (optional) object of alerting data request.
|
|
* @param array $tasks[]['request']['lld'] (optional) object of lld cache data request.
|
|
* @param array $tasks[]['proxyid'] (optional) Proxy to get diagnostic data about.
|
|
*
|
|
* @return array
|
|
*/
|
|
public function create(array $tasks): array {
|
|
$check_now_itemids = $this->validateCreate($tasks);
|
|
|
|
$tasks_by_types = [
|
|
ZBX_TM_DATA_TYPE_DIAGINFO => [],
|
|
ZBX_TM_DATA_TYPE_PROXYIDS => [],
|
|
ZBX_TM_TASK_CHECK_NOW => []
|
|
];
|
|
|
|
foreach ($tasks as $index => $task) {
|
|
if ($task['type'] == ZBX_TM_TASK_CHECK_NOW) {
|
|
$tasks_by_types[$task['type']][$index] = [
|
|
'type' => $task['type'],
|
|
'request' => [
|
|
'itemid' => $check_now_itemids[$task['request']['itemid']]
|
|
]
|
|
];
|
|
}
|
|
else {
|
|
$tasks_by_types[$task['type']][$index] = $task;
|
|
}
|
|
}
|
|
|
|
$return = $this->createTasksDiagInfo($tasks_by_types[ZBX_TM_DATA_TYPE_DIAGINFO])
|
|
+ $this->createTasksProxyIds($tasks_by_types[ZBX_TM_DATA_TYPE_PROXYIDS])
|
|
+ $this->createTasksCheckNow($tasks_by_types[ZBX_TM_TASK_CHECK_NOW]);
|
|
|
|
ksort($return);
|
|
|
|
return ['taskids' => array_values($return)];
|
|
}
|
|
|
|
/**
|
|
* Validates the input for create method and return valid item IDs. Meaning that if dependent item ID was given, try
|
|
* to find a valid master item. If valid master items were found return those item IDs.
|
|
*
|
|
* @param array $tasks Tasks to validate.
|
|
*
|
|
* @throws APIException if the input is invalid.
|
|
*
|
|
* @return array
|
|
*/
|
|
protected function validateCreate(array &$tasks): array {
|
|
$api_input_rules = ['type' => API_OBJECTS, 'flags' => API_NOT_EMPTY | API_NORMALIZE, 'fields' => [
|
|
'type' => ['type' => API_INT32, 'flags' => API_REQUIRED, 'in' => implode(',', [ZBX_TM_DATA_TYPE_DIAGINFO, ZBX_TM_DATA_TYPE_PROXYIDS, ZBX_TM_TASK_CHECK_NOW])],
|
|
'request' => ['type' => API_MULTIPLE, 'flags' => API_REQUIRED, 'rules' => [
|
|
['if' => ['field' => 'type', 'in' => ZBX_TM_DATA_TYPE_DIAGINFO], 'type' => API_OBJECT, 'fields' => [
|
|
'historycache' => ['type' => API_OBJECT, 'fields' => [
|
|
'stats' => ['type' => API_OUTPUT, 'in' => implode(',', ['items', 'values', 'memory', 'memory.data', 'memory.index']), 'default' => API_OUTPUT_EXTEND],
|
|
'top' => ['type' => API_OBJECT, 'fields' => [
|
|
'values' => ['type' => API_INT32]
|
|
]]
|
|
]],
|
|
'valuecache' => ['type' => API_OBJECT, 'fields' => [
|
|
'stats' => ['type' => API_OUTPUT, 'in' => implode(',', ['items', 'values', 'memory', 'mode']), 'default' => API_OUTPUT_EXTEND],
|
|
'top' => ['type' => API_OBJECT, 'fields' => [
|
|
'values' => ['type' => API_INT32],
|
|
'request.values' => ['type' => API_INT32]
|
|
]]
|
|
]],
|
|
'preprocessing' => ['type' => API_OBJECT, 'fields' => [
|
|
'stats' => ['type' => API_OUTPUT, 'in' => implode(',', ['values', 'preproc.values']), 'default' => API_OUTPUT_EXTEND],
|
|
'top' => ['type' => API_OBJECT, 'fields' => [
|
|
'values' => ['type' => API_INT32]
|
|
]]
|
|
]],
|
|
'alerting' => ['type' => API_OBJECT, 'fields' => [
|
|
'stats' => ['type' => API_OUTPUT, 'in' => 'alerts', 'default' => API_OUTPUT_EXTEND],
|
|
'top' => ['type' => API_OBJECT, 'fields' => [
|
|
'media.alerts' => ['type' => API_INT32],
|
|
'source.alerts' => ['type' => API_INT32]
|
|
]]
|
|
]],
|
|
'lld' => ['type' => API_OBJECT, 'fields' => [
|
|
'stats' => ['type' => API_OUTPUT, 'in' => implode(',', ['rules', 'values']), 'default' => API_OUTPUT_EXTEND],
|
|
'top' => ['type' => API_OBJECT, 'fields' => [
|
|
'values' => ['type' => API_INT32]
|
|
]]
|
|
]]
|
|
]],
|
|
['if' => ['field' => 'type', 'in' => ZBX_TM_DATA_TYPE_PROXYIDS], 'type' => API_OBJECT, 'fields' => [
|
|
'proxyids' => ['type' => API_IDS, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'uniq' => true]
|
|
]],
|
|
['if' => ['field' => 'type', 'in' => ZBX_TM_TASK_CHECK_NOW], 'type' => API_OBJECT, 'fields' => [
|
|
'itemid' => ['type' => API_ID, 'flags' => API_REQUIRED]
|
|
]]
|
|
]],
|
|
'proxyid' => ['type' => API_ID, 'default' => 0]
|
|
]];
|
|
|
|
if (!CApiInputValidator::validate($api_input_rules, $tasks, '/', $error)) {
|
|
self::exception(ZBX_API_ERROR_PARAMETERS, $error);
|
|
}
|
|
|
|
$min_permissions = USER_TYPE_ZABBIX_USER;
|
|
$itemids_editable = [];
|
|
$proxyids = [];
|
|
|
|
foreach ($tasks as $task) {
|
|
switch ($task['type']) {
|
|
case ZBX_TM_DATA_TYPE_DIAGINFO:
|
|
$min_permissions = USER_TYPE_SUPER_ADMIN;
|
|
|
|
$proxyids[$task['proxyid']] = true;
|
|
break;
|
|
|
|
case ZBX_TM_DATA_TYPE_PROXYIDS:
|
|
$min_permissions = USER_TYPE_SUPER_ADMIN;
|
|
|
|
$proxyids = array_fill_keys($task['request']['proxyids'], true);
|
|
break;
|
|
|
|
case ZBX_TM_TASK_CHECK_NOW:
|
|
$itemids_editable[$task['request']['itemid']] = true;
|
|
break;
|
|
}
|
|
}
|
|
unset($proxyids[0]);
|
|
|
|
if (self::$userData['type'] < $min_permissions) {
|
|
self::exception(ZBX_API_ERROR_PERMISSIONS, _('You do not have permission to perform this operation.'));
|
|
}
|
|
|
|
$this->checkProxyIds(array_keys($proxyids));
|
|
$itemids_editable = $this->checkEditableItems(array_keys($itemids_editable));
|
|
|
|
return $itemids_editable;
|
|
}
|
|
|
|
/**
|
|
* Create ZBX_TM_TASK_CHECK_NOW tasks.
|
|
*
|
|
* @param array $tasks Request object for tasks to create.
|
|
* @param string|array $tasks[]['request']['itemid'] Item or LLD rule IDs to create tasks for.
|
|
*
|
|
* @throws APIException
|
|
*
|
|
* @return array
|
|
*/
|
|
protected function createTasksCheckNow(array $tasks): array {
|
|
if (!$tasks) {
|
|
return [];
|
|
}
|
|
|
|
$itemids = [];
|
|
$return = [];
|
|
|
|
foreach ($tasks as $index => $task) {
|
|
$itemids[$index] = $task['request']['itemid'];
|
|
}
|
|
|
|
// Check if tasks for items and LLD rules already exist.
|
|
$db_tasks = DBselect(
|
|
'SELECT t.taskid,tcn.itemid'.
|
|
' FROM task t,task_check_now tcn'.
|
|
' WHERE t.taskid=tcn.taskid'.
|
|
' AND t.type='.ZBX_TM_TASK_CHECK_NOW.
|
|
' AND t.status='.ZBX_TM_STATUS_NEW.
|
|
' AND '.dbConditionId('tcn.itemid', $itemids)
|
|
);
|
|
|
|
while ($db_task = DBfetch($db_tasks)) {
|
|
foreach (array_keys($itemids, $db_task['itemid']) as $index) {
|
|
$return[$index] = $db_task['taskid'];
|
|
unset($itemids[$index]);
|
|
}
|
|
}
|
|
|
|
// Create new tasks.
|
|
if ($itemids) {
|
|
$item_cnt = count(array_keys(array_flip($itemids)));
|
|
$taskid = DB::reserveIds('task', $item_cnt);
|
|
$task_rows = [];
|
|
$task_check_now_rows = [];
|
|
$time = time();
|
|
$itemids_taskids = [];
|
|
|
|
foreach ($itemids as $index => $itemid) {
|
|
// Use already existing task ID and do not create a duplicate record in DB.
|
|
if (array_key_exists($itemid, $itemids_taskids)) {
|
|
$return[$index] = $itemids_taskids[$itemid];
|
|
}
|
|
else {
|
|
$task_rows[] = [
|
|
'taskid' => $taskid,
|
|
'type' => ZBX_TM_TASK_CHECK_NOW,
|
|
'status' => ZBX_TM_STATUS_NEW,
|
|
'clock' => $time,
|
|
'ttl' => SEC_PER_HOUR
|
|
];
|
|
$task_check_now_rows[] = [
|
|
'taskid' => $taskid,
|
|
'itemid' => $itemid,
|
|
'parent_taskid' => $taskid
|
|
];
|
|
|
|
$return[$index] = $taskid;
|
|
$itemids_taskids[$itemid] = $taskid;
|
|
$taskid = bcadd($taskid, 1, 0);
|
|
}
|
|
}
|
|
|
|
DB::insertBatch('task', $task_rows, false);
|
|
DB::insertBatch('task_check_now', $task_check_now_rows, false);
|
|
}
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Create ZBX_TM_DATA_TYPE_DIAGINFO tasks.
|
|
*
|
|
* @param array $tasks[]
|
|
* @param array $tasks[]['request']['historycache'] (optional) object of history cache data request.
|
|
* @param array $tasks[]['request']['valuecache'] (optional) object of value cache data request.
|
|
* @param array $tasks[]['request']['preprocessing'] (optional) object of preprocessing data request.
|
|
* @param array $tasks[]['request']['alerting'] (optional) object of alerting data request.
|
|
* @param array $tasks[]['request']['lld'] (optional) object of lld cache data request.
|
|
* @param array $tasks[]['proxyid'] Proxy to get diagnostic data about.
|
|
*
|
|
* @throws APIException
|
|
*
|
|
* @return array
|
|
*/
|
|
protected function createTasksDiagInfo(array $tasks): array {
|
|
$task_rows = [];
|
|
$task_data_rows = [];
|
|
$return = [];
|
|
$taskid = DB::reserveIds('task', count($tasks));
|
|
|
|
foreach ($tasks as $index => $task) {
|
|
$task_rows[] = [
|
|
'taskid' => $taskid,
|
|
'type' => ZBX_TM_TASK_DATA,
|
|
'status' => ZBX_TM_STATUS_NEW,
|
|
'clock' => time(),
|
|
'ttl' => SEC_PER_HOUR,
|
|
'proxyid' => $task['proxyid']
|
|
];
|
|
|
|
$task_data_rows[] = [
|
|
'taskid' => $taskid,
|
|
'type' => $task['type'],
|
|
'data' => json_encode($task['request']),
|
|
'parent_taskid' => $taskid
|
|
];
|
|
|
|
$return[$index] = $taskid;
|
|
$taskid = bcadd($taskid, 1, 0);
|
|
}
|
|
|
|
DB::insertBatch('task', $task_rows, false);
|
|
DB::insertBatch('task_data', $task_data_rows, false);
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* @param array $tasks
|
|
*
|
|
* @return array
|
|
*/
|
|
protected function createTasksProxyIds(array $tasks): array {
|
|
$task_rows = [];
|
|
$task_data_rows = [];
|
|
$proxyids = [];
|
|
$return = [];
|
|
$taskid = DB::reserveIds('task', count($tasks));
|
|
|
|
foreach ($tasks as $index => $task) {
|
|
$task_rows[] = [
|
|
'taskid' => $taskid,
|
|
'type' => ZBX_TM_TASK_DATA,
|
|
'status' => ZBX_TM_STATUS_NEW,
|
|
'clock' => time(),
|
|
'ttl' => SEC_PER_HOUR,
|
|
'proxyid' => null
|
|
];
|
|
|
|
$task_data_rows[] = [
|
|
'taskid' => $taskid,
|
|
'type' => ZBX_TM_DATA_TYPE_PROXYIDS,
|
|
'data' => json_encode([
|
|
'proxyids' => $task['request']['proxyids']
|
|
]),
|
|
'parent_taskid' => $taskid
|
|
];
|
|
|
|
$proxyids += array_flip($task['request']['proxyids']);
|
|
|
|
$return[$index] = $taskid;
|
|
$taskid = bcadd($taskid, 1, 0);
|
|
}
|
|
|
|
DB::insertBatch('task', $task_rows, false);
|
|
DB::insertBatch('task_data', $task_data_rows, false);
|
|
|
|
if ($proxyids) {
|
|
$proxies = API::Proxy()->get([
|
|
'output' => ['name'],
|
|
'proxyids' => array_keys($proxyids),
|
|
'preservekeys' => true
|
|
]);
|
|
|
|
foreach ($proxies as $proxyid => $proxy) {
|
|
self::addAuditLog(CAudit::ACTION_CONFIG_REFRESH, CAudit::RESOURCE_PROXY, [
|
|
$proxyid => [
|
|
'proxyid' => $proxyid,
|
|
'name' => $proxy['name']
|
|
]
|
|
]);
|
|
}
|
|
}
|
|
|
|
return $return;
|
|
}
|
|
|
|
protected function applyQueryOutputOptions($tableName, $tableAlias, array $options, array $sql_parts) {
|
|
$sql_parts = parent::applyQueryOutputOptions($tableName, $tableAlias, $options, $sql_parts);
|
|
|
|
if ($this->outputIsRequested('request', $options['output'])) {
|
|
$sql_parts['left_join'][] = ['alias' => 'req', 'table' => 'task_data', 'using' => 'parent_taskid'];
|
|
$sql_parts['left_table'] = ['alias' => $this->tableAlias, 'table' => $this->tableName()];
|
|
|
|
$sql_parts = $this->addQuerySelect('req.data AS request_data', $sql_parts);
|
|
}
|
|
|
|
if ($this->outputIsRequested('result', $options['output'])) {
|
|
$sql_parts['left_join'][] = ['alias' => 'resp', 'table' => 'task_result', 'using' => 'parent_taskid'];
|
|
$sql_parts['left_table'] = ['alias' => $this->tableAlias, 'table' => $this->tableName()];
|
|
|
|
$sql_parts = $this->addQuerySelect('resp.info AS result_info', $sql_parts);
|
|
$sql_parts = $this->addQuerySelect('resp.status AS result_status', $sql_parts);
|
|
}
|
|
|
|
return $sql_parts;
|
|
}
|
|
|
|
/**
|
|
* Validate user permissions to items and LLD rules;
|
|
* Check if requested items are allowed to make 'check now' operation;
|
|
* Check if items are monitored and they belong to monitored hosts;
|
|
* Check if given items are dependent items. If so, find valid master items. Master item must also be monitored
|
|
* and of valid type. Don't return the same dependent item IDs, but return the top level master item IDs.
|
|
*
|
|
* @param array $itemids
|
|
*
|
|
* @throws APIException
|
|
*
|
|
* @return array
|
|
*/
|
|
protected function checkEditableItems(array $itemids): array {
|
|
if (!$itemids) {
|
|
return [];
|
|
}
|
|
|
|
/*
|
|
* Array keys are the original item IDs given by user, but values are item IDs than can change whether item
|
|
* is dependent or not. If item is dependent key remains the same, but value changes to master item ID. Until
|
|
* the value is changed to top most master item ID.
|
|
*/
|
|
$itemid_mapping = array_combine($itemids, $itemids);
|
|
|
|
// Check permissions.
|
|
$items = API::Item()->get([
|
|
'output' => ['type', 'name', 'status', 'flags', 'master_itemid'],
|
|
'selectHosts' => ['name', 'status'],
|
|
'itemids' => $itemids,
|
|
'editable' => !self::checkAccess(CRoleHelper::ACTIONS_INVOKE_EXECUTE_NOW),
|
|
'preservekeys' => true
|
|
]);
|
|
|
|
$itemids_cnt = count($itemids);
|
|
|
|
if (count($items) != $itemids_cnt) {
|
|
$items += API::DiscoveryRule()->get([
|
|
'output' => ['type', 'name', 'status', 'flags', 'master_itemid'],
|
|
'selectHosts' => ['name', 'status'],
|
|
'itemids' => $itemids,
|
|
'editable' => !self::checkAccess(CRoleHelper::ACTIONS_INVOKE_EXECUTE_NOW),
|
|
'preservekeys' => true
|
|
]);
|
|
|
|
if (count($items) != $itemids_cnt) {
|
|
self::exception(ZBX_API_ERROR_PERMISSIONS,
|
|
_('No permissions to referred object or it does not exist!')
|
|
);
|
|
}
|
|
}
|
|
|
|
// Validate item and LLD rule type and status.
|
|
$allowed_types = checkNowAllowedTypes();
|
|
$master_itemids = [];
|
|
|
|
// Check item and LLD rule first level. Collect master item IDs if type is dependent.
|
|
foreach ($items as $itemid => $item) {
|
|
if (!in_array($item['type'], $allowed_types)) {
|
|
self::exception(ZBX_API_ERROR_PARAMETERS,
|
|
_s('Cannot send request: %1$s.',
|
|
($item['flags'] == ZBX_FLAG_DISCOVERY_RULE)
|
|
? _('wrong discovery rule type')
|
|
: _('wrong item type')
|
|
)
|
|
);
|
|
}
|
|
|
|
if ($item['status'] != ITEM_STATUS_ACTIVE || $item['hosts'][0]['status'] != HOST_STATUS_MONITORED) {
|
|
$host_name = $item['hosts'][0]['name'];
|
|
$problem = ($item['flags'] == ZBX_FLAG_DISCOVERY_RULE)
|
|
? _s('discovery rule "%1$s" on host "%2$s" is not monitored', $item['name'], $host_name)
|
|
: _s('item "%1$s" on host "%2$s" is not monitored', $item['name'], $host_name);
|
|
self::exception(ZBX_API_ERROR_PARAMETERS, _s('Cannot send request: %1$s.', $problem));
|
|
}
|
|
|
|
// Collect master item IDs and real item IDs.
|
|
if ($item['type'] == ITEM_TYPE_DEPENDENT) {
|
|
$master_itemids[$item['master_itemid']] = $itemid;
|
|
|
|
// Replace the dependent item IDs with master item ID.
|
|
$itemid_mapping[$itemid] = $item['master_itemid'];
|
|
}
|
|
}
|
|
|
|
// Put already collected items in cache.
|
|
if ($master_itemids) {
|
|
$this->item_cache = $items;
|
|
|
|
// Get master items.
|
|
while ($master_itemids) {
|
|
// Get already known items from cache or DB.
|
|
$master_items = $this->getMasterItems(array_keys($master_itemids));
|
|
$master_itemids = [];
|
|
|
|
// Check the master item type and status.
|
|
foreach ($master_items as $itemid => $item) {
|
|
if (!in_array($item['type'], $allowed_types)) {
|
|
self::exception(ZBX_API_ERROR_PARAMETERS,
|
|
_s('Cannot send request: %1$s.', _('wrong master item type'))
|
|
);
|
|
}
|
|
|
|
if ($item['status'] != ITEM_STATUS_ACTIVE || $item['hosts'][0]['status'] != HOST_STATUS_MONITORED) {
|
|
self::exception(ZBX_API_ERROR_PARAMETERS, _s('Cannot send request: %1$s.',
|
|
_s('item "%1$s" on host "%2$s" is not monitored', $item['name'], $item['hosts'][0]['name'])
|
|
));
|
|
}
|
|
|
|
/*
|
|
* If the master item was also another dependent item, add master item IDs for next loop, otherwise
|
|
* store the item ID. This will replace the original item ID from request.
|
|
*/
|
|
if ($item['type'] == ITEM_TYPE_DEPENDENT) {
|
|
// Look matching items and replace once again with master item ID.
|
|
foreach ($itemid_mapping as &$itemid_new) {
|
|
if (bccomp($itemid, $itemid_new) == 0) {
|
|
$itemid_new = $item['master_itemid'];
|
|
}
|
|
}
|
|
unset($itemid_new);
|
|
|
|
$master_itemids[$item['master_itemid']] = $itemid;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Returns both original item IDs as keys and real item IDs as values.
|
|
return $itemid_mapping;
|
|
}
|
|
|
|
/**
|
|
* Find master items by given item IDs either stored in cache or DB. Returns the item if found.
|
|
*
|
|
* @param array $itemids An array of master item IDs.
|
|
*
|
|
* @throws APIException if item is not found or user has no permissions.
|
|
*
|
|
* @return array
|
|
*/
|
|
private function getMasterItems(array $itemids): array {
|
|
$items = [];
|
|
|
|
// First try get items from cache if possible.
|
|
foreach ($itemids as $num => $itemid) {
|
|
if (array_key_exists($itemid, $this->item_cache)) {
|
|
$item = $this->item_cache[$itemid];
|
|
$items[$itemid] = $item;
|
|
unset($itemids[$num]);
|
|
}
|
|
}
|
|
|
|
// If some items were not found in cache, select them from DB.
|
|
if ($itemids) {
|
|
$items_db = API::Item()->get([
|
|
'output' => ['type', 'name', 'status', 'flags', 'master_itemid'],
|
|
'selectHosts' => ['name', 'status'],
|
|
'itemids' => $itemids,
|
|
'editable' => !self::checkAccess(CRoleHelper::ACTIONS_INVOKE_EXECUTE_NOW),
|
|
'preservekeys' => true
|
|
]);
|
|
|
|
if (!$items_db) {
|
|
self::exception(ZBX_API_ERROR_PERMISSIONS,
|
|
_('No permissions to referred object or it does not exist!')
|
|
);
|
|
}
|
|
|
|
// Add newly found items to cache.
|
|
$this->item_cache += $items_db;
|
|
|
|
// Append newly found items to items requested from cache.
|
|
$items += $items_db;
|
|
}
|
|
|
|
// Return only requested items either from cache or DB.
|
|
return $items;
|
|
}
|
|
|
|
/**
|
|
* Function to check if specified proxies exist.
|
|
*
|
|
* @param array $proxyids Proxy IDs to check.
|
|
*
|
|
* @throws Exception
|
|
*/
|
|
protected function checkProxyIds(array $proxyids): void {
|
|
if (!$proxyids) {
|
|
return;
|
|
}
|
|
|
|
$proxies = API::Proxy()->get([
|
|
'countOutput' => true,
|
|
'proxyids' => $proxyids
|
|
]);
|
|
|
|
if ($proxies != count($proxyids)) {
|
|
self::exception(ZBX_API_ERROR_PERMISSIONS, _('No permissions to referred object or it does not exist!'));
|
|
}
|
|
}
|
|
}
|