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.
zabbix/ui/app/controllers/CControllerPopupMassupdateI...

446 lines
13 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.
**/
require_once dirname(__FILE__).'/../../include/forms.inc.php';
class CControllerPopupMassupdateItem extends CController {
protected function checkInput() {
$fields = [
'context' => 'required|string|in host,template',
'ids' => 'required|array_id',
'prototype' => 'required|in 0,1',
'update' => 'in 1',
'visible' => 'array',
'parent_discoveryid' => 'id',
'history_mode' => 'in '.implode(',', [ITEM_STORAGE_OFF, ITEM_STORAGE_CUSTOM]),
'trends_mode' => 'in '.implode(',', [ITEM_STORAGE_OFF, ITEM_STORAGE_CUSTOM]),
'mass_update_tags' => 'in '.implode(',', [ZBX_ACTION_ADD, ZBX_ACTION_REPLACE, ZBX_ACTION_REMOVE]),
'delay_flex' => 'array',
// The fields used for all item types.
'type' => 'int32',
'value_type' => 'in '.implode(',', [ITEM_VALUE_TYPE_UINT64, ITEM_VALUE_TYPE_FLOAT, ITEM_VALUE_TYPE_STR, ITEM_VALUE_TYPE_LOG, ITEM_VALUE_TYPE_TEXT, ITEM_VALUE_TYPE_BINARY]),
'units' => 'string',
'history' => 'string',
'trends' => 'string',
'valuemapid' => 'id',
'logtimefmt' => 'string',
'description' => 'string',
'status' => 'in '.implode(',', [ITEM_STATUS_ACTIVE, ITEM_STATUS_DISABLED]),
'discover' => 'in '.ZBX_PROTOTYPE_DISCOVER.','.ZBX_PROTOTYPE_NO_DISCOVER,
'tags' => 'array',
'preprocessing' => 'array',
// The fields used for multiple item types.
'interfaceid' => 'id',
'authtype' => 'string',
'username' => 'string',
'password' => 'string',
'timeout' => 'string',
'delay' => 'string',
'trapper_hosts' => 'string',
// Dependent item type specific fields.
'master_itemid' => 'id',
// HTTP Agent item type specific fields.
'url' => 'string',
'post_type' => 'in '.implode(',', [ZBX_POSTTYPE_RAW, ZBX_POSTTYPE_JSON, ZBX_POSTTYPE_XML]),
'posts' => 'string',
'headers' => 'array',
'allow_traps' => 'in '.implode(',', [HTTPCHECK_ALLOW_TRAPS_ON, HTTPCHECK_ALLOW_TRAPS_OFF]),
// JMX item type specific fields.
'jmx_endpoint' => 'string',
// SSH item type specific fields.
'publickey' => 'string',
'privatekey' => 'string'
];
$ret = $this->validateInput($fields);
if (!$ret) {
$this->setResponse(
(new CControllerResponseData(['main_block' => json_encode([
'error' => [
'messages' => array_column(get_and_clear_messages(), 'message')
]
])]))->disableView()
);
}
return $ret;
}
protected function checkPermissions() {
if ($this->getInput('prototype') == 1) {
$count = API::ItemPrototype()->get([
'countOutput' => true,
'itemids' => $this->getInput('ids'),
'editable' => true
]);
}
else {
$count = API::Item()->get([
'countOutput' => true,
'itemids' => $this->getInput('ids'),
'editable' => true
]);
}
return $count != 0;
}
protected function doAction() {
$this->setResponse($this->hasInput('update') ? $this->update() : $this->form());
}
/**
* Handle item mass update action.
*
* @return CControllerResponse
*/
protected function update(): CControllerResponse {
$items_count = count($this->getInput('ids'));
$item_prototypes = (bool) $this->getInput('prototype', false);
try {
$input = [
'type' => DB::getDefault('items', 'type'),
'value_type' => ITEM_VALUE_TYPE_UINT64,
'units' => DB::getDefault('items', 'units'),
'history' => ITEM_NO_STORAGE_VALUE,
'trends' => ITEM_NO_STORAGE_VALUE,
'valuemapid' => 0,
'logtimefmt' => DB::getDefault('items', 'logtimefmt'),
'description' => DB::getDefault('items', 'description'),
'status' => DB::getDefault('items', 'status'),
'discover' => DB::getDefault('items', 'discover'),
'tags' => [],
'preprocessing' => [],
// The fields used for multiple item types.
'interfaceid' => 0,
'authtype' => DB::getDefault('items', 'authtype'),
'username' => DB::getDefault('items', 'username'),
'password' => DB::getDefault('items', 'password'),
'timeout' => '',
'delay' => DB::getDefault('items', 'delay'),
'trapper_hosts' => DB::getDefault('items', 'trapper_hosts'),
// Dependent item type specific fields.
'master_itemid' => 0,
// HTTP Agent item type specific fields.
'url' => DB::getDefault('items', 'url'),
'post_type' => DB::getDefault('items', 'post_type'),
'posts' => DB::getDefault('items', 'posts'),
'headers' => [],
'allow_traps' => DB::getDefault('items', 'allow_traps'),
// JMX item type specific fields.
'jmx_endpoint' => DB::getDefault('items', 'jmx_endpoint'),
// SSH item type specific fields.
'publickey' => DB::getDefault('items', 'publickey'),
'privatekey' => DB::getDefault('items', 'privatekey')
];
$input = array_intersect_key($input, $this->getInput('visible', []));
$this->getInputs($input, array_keys($input));
$options = [];
if (array_key_exists('tags', $input)) {
$input['tags'] = prepareItemTags($input['tags']);
$api_input_rules = ['type' => API_OBJECTS, 'uniq' => [['tag', 'value']], 'fields' => [
'tag' => ['type' => API_STRING_UTF8],
'value' => ['type' => API_STRING_UTF8]
]];
if (!CApiInputValidator::validateUniqueness($api_input_rules, $input['tags'], '/tags', $error)) {
error($error);
throw new Exception();
}
$tag_values = [];
foreach ($input['tags'] as $tag) {
$tag_values[$tag['tag']][] = $tag['value'];
}
$options['selectTags'] = ['tag', 'value'];
}
if (array_key_exists('preprocessing', $input)) {
$input['preprocessing'] = normalizeItemPreprocessingSteps($input['preprocessing']);
}
if (array_key_exists('delay', $input)) {
$delay_flex = $this->getInput('delay_flex', []);
if (!isValidCustomIntervals($delay_flex)) {
throw new Exception();
}
$input['delay'] = getDelayWithCustomIntervals($input['delay'], $delay_flex);
}
if (array_key_exists('headers', $input)) {
$input['headers'] = prepareItemHeaders($input['headers']);
}
$itemids = $this->getInput('ids');
if ($item_prototypes) {
$db_items = API::ItemPrototype()->get([
'output' => ['type', 'key_', 'value_type', 'templateid', 'authtype', 'allow_traps'],
'selectHosts' => ['status'],
'itemids' => $itemids,
'preservekeys' => true
] + $options);
}
else {
$db_items = API::Item()->get([
'output' => ['type', 'key_', 'value_type', 'templateid', 'flags', 'authtype', 'allow_traps'],
'selectHosts' => ['status'],
'itemids' => $itemids,
'preservekeys' => true
] + $options);
}
$items = [];
foreach ($itemids as $itemid) {
$db_item = $db_items[$itemid];
if ($item_prototypes) {
$db_item['flags'] = ZBX_FLAG_DISCOVERY_PROTOTYPE;
}
$item = array_intersect_key($input, getSanitizedItemFields($input + $db_item));
if (array_key_exists('tags', $input)) {
$item['tags'] = $this->getTagsToUpdate($db_item, $tag_values);
}
if ($item) {
$items[] = ['itemid' => $itemid] + $item;
}
}
$result = true;
if ($items) {
if ($item_prototypes) {
$response = API::ItemPrototype()->update($items);
}
else {
$response = API::Item()->update($items);
}
if ($response === false) {
throw new Exception();
}
}
}
catch (Exception $e) {
$result = false;
CMessageHelper::setErrorTitle(
$item_prototypes
? _n('Cannot update item prototype', 'Cannot update item prototypes', $items_count)
: _n('Cannot update item', 'Cannot update items', $items_count)
);
}
if ($result) {
$messages = CMessageHelper::getMessages();
$output = ['title' => $item_prototypes
? _n('Item prototype updated', 'Item prototypes updated', $items_count)
: _n('Item updated', 'Items updated', $items_count)
];
if (count($messages)) {
$output['messages'] = array_column($messages, 'message');
}
}
else {
$output['error'] = [
'title' => CMessageHelper::getTitle(),
'messages' => array_column(get_and_clear_messages(), 'message')
];
}
return (new CControllerResponseData(['main_block' => json_encode($output)]))->disableView();
}
/**
* Get item tags to update or null if no tags to update found.
*
* @param array $db_item
* @param array $tag_values
*
* @return array
*/
private function getTagsToUpdate(array $db_item, array $tag_values): ?array {
$tags = [];
switch ($this->getInput('mass_update_tags', ZBX_ACTION_ADD)) {
case ZBX_ACTION_ADD:
foreach ($db_item['tags'] as $db_tag) {
if (array_key_exists($db_tag['tag'], $tag_values)
&& in_array($db_tag['value'], $tag_values[$db_tag['tag']])) {
unset($tag_values[$db_tag['tag']][$db_tag['value']]);
}
}
foreach ($tag_values as $tag => $values) {
foreach ($values as $value) {
$tags[] = ['tag' => (string) $tag, 'value' => $value];
}
}
$tags = array_merge($db_item['tags'], $tags);
break;
case ZBX_ACTION_REPLACE:
foreach ($tag_values as $tag => $values) {
foreach ($values as $value) {
$tags[] = ['tag' => (string) $tag, 'value' => $value];
}
}
CArrayHelper::sort($tags, ['tag', 'value']);
CArrayHelper::sort($db_item['tags'], ['tag', 'value']);
break;
case ZBX_ACTION_REMOVE:
foreach ($db_item['tags'] as $db_tag) {
if (!array_key_exists($db_tag['tag'], $tag_values)
|| !in_array($db_tag['value'], $tag_values[$db_tag['tag']])) {
$tags[] = ['tag' => $db_tag['tag'], 'value' => $db_tag['value']];
}
}
break;
}
return $tags;
}
/**
* Handle item mass update form initialization.
*
* @return CControllerResponse
*/
protected function form(): CControllerResponse {
$data = [
'action' => $this->getAction(),
'context' => $this->getInput('context'),
'delay_flex' => [['delay' => '', 'period' => '', 'type' => ITEM_DELAY_FLEXIBLE]],
'ids' => $this->getInput('ids'),
'initial_item_type' => null,
'interfaceids' => [],
'interfaces' => [],
'multiple_interface_types' => false,
'prototype' => $this->getInput('prototype'),
'user' => ['debug_mode' => $this->getDebugMode()],
'title' => _('Mass update')
];
if ($data['prototype']) {
$data['parent_discoveryid'] = $this->getInput('parent_discoveryid', 0);
$data += [
'location_url' => (new CUrl('disc_prototypes.php'))
->setArgument('context', $this->getInput('context'))
->setArgument('parent_discoveryid', $data['parent_discoveryid'])
->getUrl(),
'preprocessing_test_type' => CControllerPopupItemTestEdit::ZBX_TEST_TYPE_ITEM_PROTOTYPE,
'preprocessing_types' => CItemPrototype::SUPPORTED_PREPROCESSING_TYPES
];
}
else {
$data += [
'location_url' => (new CUrl('items.php'))
->setArgument('context', $this->getInput('context'))
->getUrl(),
'preprocessing_test_type' => CControllerPopupItemTestEdit::ZBX_TEST_TYPE_ITEM,
'preprocessing_types' => CItem::SUPPORTED_PREPROCESSING_TYPES
];
}
if ($data['context'] === 'host') {
$hosts = API::Host()->get([
'output' => ['hostid', 'flags'],
'itemids' => $data['ids'],
'selectInterfaces' => ['interfaceid', 'main', 'type', 'useip', 'ip', 'dns', 'port', 'details'],
'limit' => 2
]);
$host = reset($hosts);
$data['discovered_host'] = ($host['flags'] == ZBX_FLAG_DISCOVERY_CREATED);
$data['hostid'] = $host['hostid'];
$data['interfaces'] = $host['interfaces'];
CArrayHelper::sort($data['interfaces'], [['field' => 'main', 'order' => ZBX_SORT_DOWN]]);
// Interfaceids for js.
foreach ($host['interfaces'] as $interface) {
$data['interfaceids'][$interface['type']][] = $interface['interfaceid'];
}
}
else {
$hosts = API::Template()->get([
'output' => ['templateid'],
'itemids' => $data['ids'],
'limit' => 2
]);
$host = reset($hosts);
$data['hostid'] = $host['templateid'];
}
$data['single_host_selected'] = (count($hosts) == 1);
if ($data['context'] === 'host' && $data['single_host_selected']) {
$entity = $data['prototype'] ? API::ItemPrototype() : API::Item();
$items = $entity->get([
'output' => ['itemid', 'type'],
'itemids' => $data['ids']
]);
$item_types = array_column($items, 'type', 'type');
$item_interface_types = array_intersect_key(
itemTypeInterface() + array_fill_keys($item_types, false),
$item_types
);
$initial_type = count($item_interface_types) ? min(array_keys($item_interface_types)) : 0;
$data['initial_item_type'] = $initial_type;
$data['multiple_interface_types'] = (count(array_unique($item_interface_types)) > 1);
$data['type'] = $initial_type;
}
$data['item_types'] = item_type2str();
unset($data['item_types'][ITEM_TYPE_HTTPTEST], $data['item_types'][ITEM_TYPE_SCRIPT]);
return new CControllerResponseData($data);
}
}