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.

1717 lines
50 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 hosts.
*/
abstract class CHostGeneral extends CHostBase {
public const ACCESS_RULES = [
'get' => ['min_user_type' => USER_TYPE_ZABBIX_USER],
'create' => ['min_user_type' => USER_TYPE_ZABBIX_ADMIN],
'update' => ['min_user_type' => USER_TYPE_ZABBIX_ADMIN],
'delete' => ['min_user_type' => USER_TYPE_ZABBIX_ADMIN],
'massadd' => ['min_user_type' => USER_TYPE_ZABBIX_ADMIN],
'massupdate' => ['min_user_type' => USER_TYPE_ZABBIX_ADMIN],
'massremove' => ['min_user_type' => USER_TYPE_ZABBIX_ADMIN]
];
/**
* Check for valid host groups and template groups.
*
* @param array $hosts
* @param array|null $db_hosts
*
* @throws APIException if groups are not valid.
*/
protected function checkGroups(array $hosts, array $db_hosts = null): void {
$id_field_name = $this instanceof CTemplate ? 'templateid' : 'hostid';
$edit_groupids = [];
foreach ($hosts as $host) {
if (!array_key_exists('groups', $host)) {
continue;
}
$groupids = array_column($host['groups'], 'groupid');
if ($db_hosts === null) {
$edit_groupids += array_flip($groupids);
}
else {
$db_groupids = array_column($db_hosts[$host[$id_field_name]]['groups'], 'groupid');
$ins_groupids = array_flip(array_diff($groupids, $db_groupids));
$del_groupids = array_flip(array_diff($db_groupids, $groupids));
$edit_groupids += $ins_groupids + $del_groupids;
}
}
if (!$edit_groupids) {
return;
}
$entity = $this instanceof CTemplate ? API::TemplateGroup() : API::HostGroup();
$count = $entity->get([
'countOutput' => true,
'groupids' => array_keys($edit_groupids),
'editable' => true
]);
if ($count != count($edit_groupids)) {
self::exception(ZBX_API_ERROR_PERMISSIONS, _('No permissions to referred object or it does not exist!'));
}
}
/**
* Check for unique host names.
*
* @param array $hosts
* @param array|null $db_hosts
*
* @throws APIException if host names are not unique.
*/
protected function checkDuplicates(array $hosts, array $db_hosts = null): void {
$id_field_name = $this instanceof CTemplate ? 'templateid' : 'hostid';
$h_names = [];
$v_names = [];
foreach ($hosts as $host) {
if (array_key_exists('host', $host)) {
if ($db_hosts === null || $host['host'] !== $db_hosts[$host[$id_field_name]]['host']) {
$h_names[] = $host['host'];
}
}
if (array_key_exists('name', $host)) {
if ($db_hosts === null || $host['name'] !== $db_hosts[$host[$id_field_name]]['name']) {
$v_names[] = $host['name'];
}
}
}
if ($h_names) {
$duplicates = DB::select('hosts', [
'output' => ['host', 'status'],
'filter' => [
'flags' => [ZBX_FLAG_DISCOVERY_NORMAL, ZBX_FLAG_DISCOVERY_CREATED],
'status' => [HOST_STATUS_MONITORED, HOST_STATUS_NOT_MONITORED, HOST_STATUS_TEMPLATE],
'host' => $h_names
],
'limit' => 1
]);
if ($duplicates) {
$error = ($duplicates[0]['status'] == HOST_STATUS_TEMPLATE)
? _s('Template with host name "%1$s" already exists.', $duplicates[0]['host'])
: _s('Host with host name "%1$s" already exists.', $duplicates[0]['host']);
self::exception(ZBX_API_ERROR_PARAMETERS, $error);
}
}
if ($v_names) {
$duplicates = DB::select('hosts', [
'output' => ['name', 'status'],
'filter' => [
'flags' => [ZBX_FLAG_DISCOVERY_NORMAL, ZBX_FLAG_DISCOVERY_CREATED],
'status' => [HOST_STATUS_MONITORED, HOST_STATUS_NOT_MONITORED, HOST_STATUS_TEMPLATE],
'name' => $v_names
],
'limit' => 1
]);
if ($duplicates) {
$error = ($duplicates[0]['status'] == HOST_STATUS_TEMPLATE)
? _s('Template with visible name "%1$s" already exists.', $duplicates[0]['name'])
: _s('Host with visible name "%1$s" already exists.', $duplicates[0]['name']);
self::exception(ZBX_API_ERROR_PARAMETERS, $error);
}
}
}
/**
* Check templates links for given data of mass API methods.
*
* @param string $method
* @param array $templateids
* @param array $db_hosts
*/
protected function massCheckTemplatesLinks(string $method, array $templateids, array $db_hosts,
array $templateids_clear = []): void {
$ins_templates = [];
$del_links = [];
$check_double_linkage = false;
$del_templates = [];
$del_links_clear = [];
foreach ($db_hosts as $hostid => $db_host) {
$db_templateids = array_column($db_host['templates'], 'templateid');
if ($method === 'massadd') {
$_templateids = array_diff($templateids, $db_templateids);
}
elseif ($method === 'massremove') {
$_templateids = array_diff($db_templateids, $templateids);
}
else {
$_templateids = $templateids;
}
$permitted_templateids = $_templateids;
$templates_count = count($permitted_templateids);
$upd_templateids = [];
if (array_key_exists('nopermissions_templates', $db_host)) {
foreach ($db_host['nopermissions_templates'] as $db_template) {
$_templateids[] = $db_template['templateid'];
$templates_count++;
$upd_templateids[] = $db_template['templateid'];
}
}
foreach ($permitted_templateids as $templateid) {
$index = array_search($templateid, $db_templateids);
if ($index !== false) {
$upd_templateids[] = $templateid;
unset($db_templateids[$index]);
}
else {
$ins_templates[$templateid][$hostid] = $_templateids;
if ($this instanceof CTemplate || $templates_count > 1) {
$check_double_linkage = true;
}
}
}
foreach ($db_templateids as $db_templateid) {
$del_links[$db_templateid][$hostid] = true;
if ($upd_templateids) {
$del_templates[$db_templateid][$hostid] = $upd_templateids;
}
if (array_key_exists($db_templateid, $templateids_clear)) {
$del_links_clear[$db_templateid][$hostid] = true;
}
}
}
if ($del_templates) {
$this->checkTriggerExpressionsOfDelTemplates($del_templates);
}
if ($del_links_clear) {
$this->checkTriggerDependenciesOfHostTriggers($del_links_clear);
}
if ($ins_templates) {
if ($this instanceof CTemplate) {
self::checkCircularLinkageNew($ins_templates, $del_links);
}
if ($check_double_linkage) {
$this->checkDoubleLinkageNew($ins_templates, $del_links, null);
}
$this->checkTriggerDependenciesOfInsTemplates($ins_templates);
$this->checkTriggerExpressionsOfInsTemplates($ins_templates);
}
}
/**
* Update table "hosts_groups" and populate hosts.groups by "hostgroupid" property.
*
* @param array $hosts
* @param array|null $db_hosts
*/
protected function updateGroups(array &$hosts, array $db_hosts = null): void {
$id_field_name = $this instanceof CTemplate ? 'templateid' : 'hostid';
$ins_hosts_groups = [];
$del_hostgroupids = [];
foreach ($hosts as &$host) {
if (!array_key_exists('groups', $host)) {
continue;
}
$db_groups = ($db_hosts !== null)
? array_column($db_hosts[$host[$id_field_name]]['groups'], null, 'groupid')
: [];
foreach ($host['groups'] as &$group) {
if (array_key_exists($group['groupid'], $db_groups)) {
$group['hostgroupid'] = $db_groups[$group['groupid']]['hostgroupid'];
unset($db_groups[$group['groupid']]);
}
else {
$ins_hosts_groups[] = [
'hostid' => $host[$id_field_name],
'groupid' => $group['groupid']
];
}
}
unset($group);
$del_hostgroupids = array_merge($del_hostgroupids, array_column($db_groups, 'hostgroupid'));
}
unset($host);
if ($del_hostgroupids) {
DB::delete('hosts_groups', ['hostgroupid' => $del_hostgroupids]);
}
if ($ins_hosts_groups) {
$hostgroupids = DB::insertBatch('hosts_groups', $ins_hosts_groups);
}
foreach ($hosts as &$host) {
if (!array_key_exists('groups', $host)) {
continue;
}
foreach ($host['groups'] as &$group) {
if (!array_key_exists('hostgroupid', $group)) {
$group['hostgroupid'] = array_shift($hostgroupids);
}
}
unset($group);
}
unset($host);
}
/**
* Update table "hosts_templates" and change objects of linked or unliked templates on target hosts or templates.
*
* @param array $hosts
* @param array|null $db_hosts
* @param array|null $upd_hostids
*/
protected function updateTemplates(array &$hosts, array &$db_hosts = null, array &$upd_hostids = null): void {
$id_field_name = $this instanceof CTemplate ? 'templateid' : 'hostid';
parent::updateTemplates($hosts, $db_hosts);
$ins_links = [];
$del_links = [];
$del_links_clear = [];
foreach ($hosts as $host) {
if (!array_key_exists('templates', $host) && !array_key_exists('templates_clear', $host)) {
continue;
}
$db_templates = ($db_hosts !== null)
? array_column($db_hosts[$host[$id_field_name]]['templates'], null, 'templateid')
: [];
if (array_key_exists('templates', $host)) {
foreach ($host['templates'] as $template) {
if (array_key_exists($template['templateid'], $db_templates)) {
unset($db_templates[$template['templateid']]);
}
else {
$ins_links[$template['templateid']][] = $host[$id_field_name];
}
}
$templates_clear = array_key_exists('templates_clear', $host)
? array_column($host['templates_clear'], null, 'templateid')
: [];
foreach ($db_templates as $del_template) {
if (array_key_exists($del_template['templateid'], $templates_clear)) {
$del_links_clear[$del_template['templateid']][] = $host[$id_field_name];
}
else {
$del_links[$del_template['templateid']][] = $host[$id_field_name];
}
}
}
elseif (array_key_exists('templates_clear', $host)) {
foreach ($host['templates_clear'] as $template) {
$del_links_clear[$template['templateid']][] = $host[$id_field_name];
}
}
}
while ($del_links_clear) {
$templateid = key($del_links_clear);
$hostids = reset($del_links_clear);
$templateids = [$templateid];
unset($del_links_clear[$templateid]);
foreach ($del_links_clear as $templateid => $_hostids) {
if ($_hostids === $hostids) {
$templateids[] = $templateid;
unset($del_links_clear[$templateid]);
}
}
self::unlinkTemplatesObjects($templateids, $hostids, true);
}
while ($del_links) {
$templateid = key($del_links);
$hostids = reset($del_links);
$templateids = [$templateid];
unset($del_links[$templateid]);
foreach ($del_links as $templateid => $_hostids) {
if ($_hostids === $hostids) {
$templateids[] = $templateid;
unset($del_links[$templateid]);
}
}
self::unlinkTemplatesObjects($templateids, $hostids);
}
while ($ins_links) {
$templateid = key($ins_links);
$hostids = reset($ins_links);
$templateids = [$templateid];
unset($ins_links[$templateid]);
foreach ($ins_links as $templateid => $_hostids) {
if ($_hostids === $hostids) {
$templateids[] = $templateid;
unset($ins_links[$templateid]);
}
}
self::linkTemplatesObjects($templateids, $hostids);
}
}
/**
* Unlink or clear objects of given templates from given hosts or templates.
*
* @param array $templateids
* @param array|null $hostids
* @param bool $clear
*/
protected static function unlinkTemplatesObjects(array $templateids, array $hostids = null,
bool $clear = false): void {
$flags = ($clear)
? [ZBX_FLAG_DISCOVERY_NORMAL, ZBX_FLAG_DISCOVERY_RULE]
: [ZBX_FLAG_DISCOVERY_NORMAL, ZBX_FLAG_DISCOVERY_RULE, ZBX_FLAG_DISCOVERY_PROTOTYPE];
// triggers
$db_triggers = DBselect(
'SELECT DISTINCT f.triggerid'.
' FROM functions f,items i'.
' WHERE f.itemid=i.itemid'.
' AND '.dbConditionInt('i.hostid', $templateids)
);
$tpl_triggerids = DBfetchColumn($db_triggers, 'triggerid');
$upd_triggers = [
ZBX_FLAG_DISCOVERY_NORMAL => [],
ZBX_FLAG_DISCOVERY_PROTOTYPE => []
];
if ($tpl_triggerids) {
$sql_distinct = ($hostids !== null) ? ' DISTINCT' : '';
$sql_from = ($hostids !== null) ? ',functions f,items i' : '';
$sql_where = ($hostids !== null)
? ' AND t.triggerid=f.triggerid'.
' AND f.itemid=i.itemid'.
' AND '.dbConditionInt('i.hostid', $hostids)
: '';
$db_triggers = DBSelect(
'SELECT'.$sql_distinct.' t.triggerid,t.flags'.
' FROM triggers t'.$sql_from.
' WHERE '.dbConditionInt('t.templateid', $tpl_triggerids).
' AND '.dbConditionInt('t.flags', $flags).
$sql_where
);
while ($db_trigger = DBfetch($db_triggers)) {
if ($clear) {
$upd_triggers[$db_trigger['flags']][$db_trigger['triggerid']] = true;
}
else {
$upd_triggers[$db_trigger['flags']][$db_trigger['triggerid']] = [
'values' => ['templateid' => 0],
'where' => ['triggerid' => $db_trigger['triggerid']]
];
}
}
if (!$clear && ($upd_triggers[ZBX_FLAG_DISCOVERY_NORMAL] || $upd_triggers[ZBX_FLAG_DISCOVERY_PROTOTYPE])) {
$db_triggers = DBselect(
'SELECT DISTINCT t.triggerid,t.flags'.
' FROM triggers t,functions f,items i,hosts h'.
' WHERE t.triggerid=f.triggerid'.
' AND f.itemid=i.itemid'.
' AND i.hostid=h.hostid'.
' AND h.status='.HOST_STATUS_TEMPLATE.
' AND '.dbConditionInt('t.triggerid', array_keys(
$upd_triggers[ZBX_FLAG_DISCOVERY_NORMAL] + $upd_triggers[ZBX_FLAG_DISCOVERY_PROTOTYPE]
))
);
while ($db_trigger = DBfetch($db_triggers)) {
$upd_triggers[$db_trigger['flags']][$db_trigger['triggerid']]['values']['uuid'] = generateUuidV4();
}
}
}
if ($upd_triggers[ZBX_FLAG_DISCOVERY_NORMAL]) {
if ($clear) {
CTriggerManager::delete(array_keys($upd_triggers[ZBX_FLAG_DISCOVERY_NORMAL]));
}
else {
DB::update('triggers', $upd_triggers[ZBX_FLAG_DISCOVERY_NORMAL]);
}
}
if ($upd_triggers[ZBX_FLAG_DISCOVERY_PROTOTYPE]) {
if ($clear) {
CTriggerPrototypeManager::delete(array_keys($upd_triggers[ZBX_FLAG_DISCOVERY_PROTOTYPE]));
}
else {
DB::update('triggers', $upd_triggers[ZBX_FLAG_DISCOVERY_PROTOTYPE]);
}
}
// graphs
$db_tpl_graphs = DBselect(
'SELECT DISTINCT g.graphid'.
' FROM graphs g,graphs_items gi,items i'.
' WHERE g.graphid=gi.graphid'.
' AND gi.itemid=i.itemid'.
' AND '.dbConditionInt('i.hostid', $templateids).
' AND '.dbConditionInt('g.flags', $flags)
);
$tpl_graphids = [];
while ($db_tpl_graph = DBfetch($db_tpl_graphs)) {
$tpl_graphids[] = $db_tpl_graph['graphid'];
}
if ($tpl_graphids) {
$upd_graphs = [
ZBX_FLAG_DISCOVERY_NORMAL => [],
ZBX_FLAG_DISCOVERY_PROTOTYPE => []
];
$sql = ($hostids !== null)
? 'SELECT DISTINCT g.graphid,g.flags'.
' FROM graphs g,graphs_items gi,items i'.
' WHERE g.graphid=gi.graphid'.
' AND gi.itemid=i.itemid'.
' AND '.dbConditionInt('g.templateid', $tpl_graphids).
' AND '.dbConditionInt('i.hostid', $hostids)
: 'SELECT g.graphid,g.flags'.
' FROM graphs g'.
' WHERE '.dbConditionInt('g.templateid', $tpl_graphids);
$db_graphs = DBSelect($sql);
while ($db_graph = DBfetch($db_graphs)) {
if ($clear) {
$upd_graphs[$db_graph['flags']][$db_graph['graphid']] = true;
}
else {
$upd_graphs[$db_graph['flags']][$db_graph['graphid']] = [
'values' => ['templateid' => 0],
'where' => ['graphid' => $db_graph['graphid']]
];
}
}
if (!$clear && ($upd_graphs[ZBX_FLAG_DISCOVERY_NORMAL] || $upd_graphs[ZBX_FLAG_DISCOVERY_PROTOTYPE])) {
$db_graphs = DBselect(
'SELECT DISTINCT g.graphid,g.flags'.
' FROM graphs g,graphs_items gi,items i,hosts h'.
' WHERE g.graphid=gi.graphid'.
' AND gi.itemid=i.itemid'.
' AND i.hostid=h.hostid'.
' AND h.status='.HOST_STATUS_TEMPLATE.
' AND '.dbConditionInt('g.graphid', array_keys(
$upd_graphs[ZBX_FLAG_DISCOVERY_NORMAL] + $upd_graphs[ZBX_FLAG_DISCOVERY_PROTOTYPE]
))
);
while ($db_graph = DBfetch($db_graphs)) {
$upd_graphs[$db_graph['flags']][$db_graph['graphid']]['values']['uuid'] = generateUuidV4();
}
}
if ($upd_graphs[ZBX_FLAG_DISCOVERY_PROTOTYPE]) {
if ($clear) {
CGraphPrototypeManager::delete(array_keys($upd_graphs[ZBX_FLAG_DISCOVERY_PROTOTYPE]));
}
else {
DB::update('graphs', $upd_graphs[ZBX_FLAG_DISCOVERY_PROTOTYPE]);
}
}
if ($upd_graphs[ZBX_FLAG_DISCOVERY_NORMAL]) {
if ($clear) {
CGraphManager::delete(array_keys($upd_graphs[ZBX_FLAG_DISCOVERY_NORMAL]));
}
else {
DB::update('graphs', $upd_graphs[ZBX_FLAG_DISCOVERY_NORMAL]);
}
}
}
if ($clear) {
CDiscoveryRule::clearTemplateObjects($templateids, $hostids);
CItem::clearTemplateObjects($templateids, $hostids);
CHttpTest::clearTemplateObjects($templateids, $hostids);
}
else {
CDiscoveryRule::unlinkTemplateObjects($templateids, $hostids);
CItem::unlinkTemplateObjects($templateids, $hostids);
CHttpTest::unlinkTemplateObjects($templateids, $hostids);
}
}
/**
* Add objects of given templates to given hosts or templates.
*
* @param array $templateids
* @param array $hostids
*/
private static function linkTemplatesObjects(array $templateids, array $hostids): void {
// TODO: Modify parameters of syncTemplates methods when complete audit log will be implementing for hosts.
$link_request = [
'templateids' => $templateids,
'hostids' => $hostids
];
foreach ($templateids as $templateid) {
// Fist link web items, so that later regular items can use web item as their master item.
Manager::HttpTest()->link($templateid, $hostids);
}
CItem::linkTemplateObjects($templateids, $hostids);
API::Trigger()->syncTemplates($link_request);
API::Graph()->syncTemplates($link_request);
CDiscoveryRule::linkTemplateObjects($templateids, $hostids);
CTriggerGeneral::syncTemplateDependencies($link_request['templateids'], $link_request['hostids']);
}
/**
* Checks if the current user has access to the given hosts and templates. Assumes the "hostid" field is valid.
*
* @param array $hostids an array of host or template IDs
*
* @throws APIException if the user doesn't have write permissions for the given hosts.
*/
protected function checkHostPermissions(array $hostids) {
if ($hostids) {
$hostids = array_unique($hostids);
$count = API::Host()->get([
'countOutput' => true,
'hostids' => $hostids,
'editable' => true
]);
if ($count == count($hostids)) {
return;
}
$count += API::Template()->get([
'countOutput' => true,
'templateids' => $hostids,
'editable' => true
]);
if ($count != count($hostids)) {
self::exception(ZBX_API_ERROR_PERMISSIONS,
_('No permissions to referred object or it does not exist!')
);
}
}
}
/**
* Allows to:
* - add hosts to groups;
* - link templates to hosts;
* - add new macros to hosts.
*
* Supported $data parameters are:
* - hosts - an array of hosts to be updated
* - templates - an array of templates to be updated
* - groups - an array of host groups to add the host to
* - templates_link - an array of templates to link to the hosts
* - macros - an array of macros to create on the host
*
* @param array $data
*
* @return array
*/
public function massAdd(array $data) {
$hostIds = zbx_objectValues($data['hosts'], 'hostid');
$templateIds = zbx_objectValues($data['templates'], 'templateid');
$allHostIds = array_merge($hostIds, $templateIds);
// add groups
if (array_key_exists('groups', $data) && $data['groups']) {
$options = ['groups' => $data['groups']];
if ($data['hosts']) {
$options += [
'hosts' => array_map(
static function($host) {
return array_intersect_key($host, array_flip(['hostid']));
},
$data['hosts']
)
];
}
if ($data['templates']) {
$options += [
'templates' => array_map(
static function($template) {
return array_intersect_key($template, array_flip(['templateid']));
},
$data['templates']
)
];
}
API::HostGroup()->massAdd($options);
}
// link templates
if (!empty($data['templates_link'])) {
$this->checkHostPermissions($allHostIds);
$this->link(zbx_objectValues(zbx_toArray($data['templates_link']), 'templateid'), $allHostIds);
}
// create macros
if (!empty($data['macros'])) {
$data['macros'] = zbx_toArray($data['macros']);
$hostMacrosToAdd = [];
foreach ($data['macros'] as $hostMacro) {
foreach ($allHostIds as $hostid) {
$hostMacro['hostid'] = $hostid;
$hostMacrosToAdd[] = $hostMacro;
}
}
API::UserMacro()->create($hostMacrosToAdd);
}
$ids = ['hostids' => $hostIds, 'templateids' => $templateIds];
return [$this->pkOption() => $ids[$this->pkOption()]];
}
/**
* Allows to:
* - remove hosts from groups;
* - unlink and clear templates from hosts;
* - remove macros from hosts.
*
* Supported $data parameters are:
* - hostids - an array of host IDs to be updated
* - templateids - an array of template IDs to be updated
* - groupids - an array of host group IDs the hosts should be removed from
* - templateids_link - an array of template IDs to unlink from the hosts
* - templateids_clear - an array of template IDs to unlink and clear from the hosts
* - macros - an array of macros to delete from the hosts
*
* @param array $data
*
* @return array
*/
public function massRemove(array $data) {
$allHostIds = array_merge($data['hostids'], $data['templateids']);
$this->checkHostPermissions($allHostIds);
if (!empty($data['templateids_link'])) {
$this->unlink(zbx_toArray($data['templateids_link']), $allHostIds);
}
if (isset($data['templateids_clear'])) {
$this->unlink(zbx_toArray($data['templateids_clear']), $allHostIds, true);
}
if (array_key_exists('macros', $data)) {
if (!$data['macros']) {
self::exception(ZBX_API_ERROR_PARAMETERS, _('Empty input parameter.'));
}
$hostMacros = API::UserMacro()->get([
'output' => ['hostmacroid'],
'hostids' => $allHostIds,
'filter' => [
'macro' => $data['macros']
]
]);
$hostMacroIds = zbx_objectValues($hostMacros, 'hostmacroid');
if ($hostMacroIds) {
API::UserMacro()->delete($hostMacroIds);
}
}
if (isset($data['groupids'])) {
$options = ['groupids' => $data['groupids']];
if ($data['hostids']) {
$options['hostids'] = $data['hostids'];
}
if ($data['templateids']) {
$options['templateids'] = $data['templateids'];
}
API::HostGroup()->massRemove($options);
}
return [$this->pkOption() => $data[$this->pkOption()]];
}
protected function link(array $templateIds, array $targetIds) {
$hosts_linkage_inserts = parent::link($templateIds, $targetIds);
$templates_hostids = [];
$link_requests = [];
foreach ($hosts_linkage_inserts as $host_tpl_ids) {
$templates_hostids[$host_tpl_ids['templateid']][] = $host_tpl_ids['hostid'];
}
foreach ($templates_hostids as $templateid => $hostids) {
// Fist link web items, so that later regular items can use web item as their master item.
Manager::HttpTest()->link($templateid, $hostids);
}
while ($templates_hostids) {
$templateid = key($templates_hostids);
$link_request = [
'hostids' => reset($templates_hostids),
'templateids' => [$templateid]
];
unset($templates_hostids[$templateid]);
foreach ($templates_hostids as $templateid => $hostids) {
if ($link_request['hostids'] === $hostids) {
$link_request['templateids'][] = $templateid;
unset($templates_hostids[$templateid]);
}
}
$link_requests[] = $link_request;
}
foreach ($link_requests as $link_request) {
CItem::linkTemplateObjects($link_request['templateids'], $link_request['hostids']);
}
foreach ($link_requests as $link_request) {
API::Trigger()->syncTemplates($link_request);
API::Graph()->syncTemplates($link_request);
}
foreach ($link_requests as $link_request){
CDiscoveryRule::linkTemplateObjects($link_request['templateids'], $link_request['hostids']);
CTriggerGeneral::syncTemplateDependencies($link_request['templateids'], $link_request['hostids']);
}
return $hosts_linkage_inserts;
}
/**
* Unlinks the templates from the given hosts. If $targetids is set to null, the templates will be unlinked from
* all hosts.
*
* @param array $templateids
* @param null|array $targetids the IDs of the hosts to unlink the templates from
* @param bool $clear delete all of the inherited objects from the hosts
*/
protected function unlink($templateids, $targetids = null, $clear = false) {
$flags = ($clear)
? [ZBX_FLAG_DISCOVERY_NORMAL, ZBX_FLAG_DISCOVERY_RULE]
: [ZBX_FLAG_DISCOVERY_NORMAL, ZBX_FLAG_DISCOVERY_RULE, ZBX_FLAG_DISCOVERY_PROTOTYPE];
// check that all triggers on templates that we unlink, don't have items from another templates
$sql = 'SELECT DISTINCT t.description'.
' FROM triggers t,functions f,items i'.
' WHERE t.triggerid=f.triggerid'.
' AND f.itemid=i.itemid'.
' AND '.dbConditionInt('i.hostid', $templateids).
' AND EXISTS ('.
'SELECT ff.triggerid'.
' FROM functions ff,items ii'.
' WHERE ff.itemid=ii.itemid'.
' AND ff.triggerid=t.triggerid'.
' AND '.dbConditionInt('ii.hostid', $templateids, true).
')'.
' AND t.flags='.ZBX_FLAG_DISCOVERY_NORMAL;
if ($dbTrigger = DBfetch(DBSelect($sql, 1))) {
self::exception(ZBX_API_ERROR_PARAMETERS,
_s('Cannot unlink trigger "%1$s", it has items from template that is left linked to host.',
$dbTrigger['description']
)
);
}
$templ_triggerids = [];
$db_triggers = DBselect(
'SELECT DISTINCT f.triggerid'.
' FROM functions f,items i'.
' WHERE f.itemid=i.itemid'.
' AND '.dbConditionInt('i.hostid', $templateids)
);
while ($db_trigger = DBfetch($db_triggers)) {
$templ_triggerids[] = $db_trigger['triggerid'];
}
$upd_triggers = [
ZBX_FLAG_DISCOVERY_NORMAL => [],
ZBX_FLAG_DISCOVERY_PROTOTYPE => []
];
if ($templ_triggerids) {
$sql_distinct = ($targetids !== null) ? ' DISTINCT' : '';
$sql_from = ($targetids !== null) ? ',functions f,items i' : '';
$sql_where = ($targetids !== null)
? ' AND t.triggerid=f.triggerid'.
' AND f.itemid=i.itemid'.
' AND '.dbConditionInt('i.hostid', $targetids)
: '';
$db_triggers = DBSelect(
'SELECT'.$sql_distinct.' t.triggerid,t.flags'.
' FROM triggers t'.$sql_from.
' WHERE '.dbConditionInt('t.templateid', $templ_triggerids).
' AND '.dbConditionInt('t.flags', $flags).
$sql_where
);
while ($db_trigger = DBfetch($db_triggers)) {
if ($clear) {
$upd_triggers[$db_trigger['flags']][$db_trigger['triggerid']] = true;
}
else {
$upd_triggers[$db_trigger['flags']][$db_trigger['triggerid']] = [
'values' => ['templateid' => 0],
'where' => ['triggerid' => $db_trigger['triggerid']]
];
}
}
if (!$clear && ($upd_triggers[ZBX_FLAG_DISCOVERY_NORMAL] || $upd_triggers[ZBX_FLAG_DISCOVERY_PROTOTYPE])) {
$db_triggers = DBselect(
'SELECT DISTINCT t.triggerid,t.flags'.
' FROM triggers t,functions f,items i,hosts h'.
' WHERE t.triggerid=f.triggerid'.
' AND f.itemid=i.itemid'.
' AND i.hostid=h.hostid'.
' AND h.status='.HOST_STATUS_TEMPLATE.
' AND '.dbConditionInt('t.triggerid', array_keys(
$upd_triggers[ZBX_FLAG_DISCOVERY_NORMAL] + $upd_triggers[ZBX_FLAG_DISCOVERY_PROTOTYPE]
))
);
while ($db_trigger = DBfetch($db_triggers)) {
$upd_triggers[$db_trigger['flags']][$db_trigger['triggerid']]['values']['uuid'] = generateUuidV4();
}
}
}
if ($upd_triggers[ZBX_FLAG_DISCOVERY_NORMAL]) {
if ($clear) {
CTriggerManager::delete(array_keys($upd_triggers[ZBX_FLAG_DISCOVERY_NORMAL]));
}
else {
DB::update('triggers', $upd_triggers[ZBX_FLAG_DISCOVERY_NORMAL]);
}
}
if ($upd_triggers[ZBX_FLAG_DISCOVERY_PROTOTYPE]) {
if ($clear) {
CTriggerPrototypeManager::delete(array_keys($upd_triggers[ZBX_FLAG_DISCOVERY_PROTOTYPE]));
}
else {
DB::update('triggers', $upd_triggers[ZBX_FLAG_DISCOVERY_PROTOTYPE]);
}
}
/* GRAPHS {{{ */
$db_tpl_graphs = DBselect(
'SELECT DISTINCT g.graphid'.
' FROM graphs g,graphs_items gi,items i'.
' WHERE g.graphid=gi.graphid'.
' AND gi.itemid=i.itemid'.
' AND '.dbConditionInt('i.hostid', $templateids).
' AND '.dbConditionInt('g.flags', $flags)
);
$tpl_graphids = [];
while ($db_tpl_graph = DBfetch($db_tpl_graphs)) {
$tpl_graphids[] = $db_tpl_graph['graphid'];
}
if ($tpl_graphids) {
$upd_graphs = [
ZBX_FLAG_DISCOVERY_NORMAL => [],
ZBX_FLAG_DISCOVERY_PROTOTYPE => []
];
$sql = ($targetids !== null)
? 'SELECT DISTINCT g.graphid,g.flags'.
' FROM graphs g,graphs_items gi,items i'.
' WHERE g.graphid=gi.graphid'.
' AND gi.itemid=i.itemid'.
' AND '.dbConditionInt('g.templateid', $tpl_graphids).
' AND '.dbConditionInt('i.hostid', $targetids)
: 'SELECT g.graphid,g.flags'.
' FROM graphs g'.
' WHERE '.dbConditionInt('g.templateid', $tpl_graphids);
$db_graphs = DBSelect($sql);
while ($db_graph = DBfetch($db_graphs)) {
if ($clear) {
$upd_graphs[$db_graph['flags']][$db_graph['graphid']] = true;
}
else {
$upd_graphs[$db_graph['flags']][$db_graph['graphid']] = [
'values' => ['templateid' => 0],
'where' => ['graphid' => $db_graph['graphid']]
];
}
}
if (!$clear && ($upd_graphs[ZBX_FLAG_DISCOVERY_NORMAL] || $upd_graphs[ZBX_FLAG_DISCOVERY_PROTOTYPE])) {
$db_graphs = DBselect(
'SELECT DISTINCT g.graphid,g.flags'.
' FROM graphs g,graphs_items gi,items i,hosts h'.
' WHERE g.graphid=gi.graphid'.
' AND gi.itemid=i.itemid'.
' AND i.hostid=h.hostid'.
' AND h.status='.HOST_STATUS_TEMPLATE.
' AND '.dbConditionInt('g.graphid', array_keys(
$upd_graphs[ZBX_FLAG_DISCOVERY_NORMAL] + $upd_graphs[ZBX_FLAG_DISCOVERY_PROTOTYPE]
))
);
while ($db_graph = DBfetch($db_graphs)) {
$upd_graphs[$db_graph['flags']][$db_graph['graphid']]['values']['uuid'] = generateUuidV4();
}
}
if ($upd_graphs[ZBX_FLAG_DISCOVERY_PROTOTYPE]) {
if ($clear) {
CGraphPrototypeManager::delete(array_keys($upd_graphs[ZBX_FLAG_DISCOVERY_PROTOTYPE]));
}
else {
DB::update('graphs', $upd_graphs[ZBX_FLAG_DISCOVERY_PROTOTYPE]);
}
}
if ($upd_graphs[ZBX_FLAG_DISCOVERY_NORMAL]) {
if ($clear) {
CGraphManager::delete(array_keys($upd_graphs[ZBX_FLAG_DISCOVERY_NORMAL]));
}
else {
DB::update('graphs', $upd_graphs[ZBX_FLAG_DISCOVERY_NORMAL]);
}
}
}
/* }}} GRAPHS */
if ($clear) {
CDiscoveryRule::clearTemplateObjects($templateids, $targetids);
CItem::clearTemplateObjects($templateids, $targetids);
CHttpTest::clearTemplateObjects($templateids, $targetids);
}
else {
CDiscoveryRule::unlinkTemplateObjects($templateids, $targetids);
CItem::unlinkTemplateObjects($templateids, $targetids);
CHttpTest::unlinkTemplateObjects($templateids, $targetids);
}
parent::unlink($templateids, $targetids);
}
protected function addRelatedObjects(array $options, array $result) {
$result = parent::addRelatedObjects($options, $result);
$hostids = array_keys($result);
// Add templates.
if ($options['selectParentTemplates'] !== null) {
if ($options['selectParentTemplates'] != API_OUTPUT_COUNT) {
$templates = [];
// Get template IDs for each host and additional field from relation table if necessary.
$hosts_templates = DBfetchArray(DBselect(
'SELECT ht.hostid,ht.templateid'.
($this->outputIsRequested('link_type', $options['selectParentTemplates'])
? ',ht.link_type'
: ''
).
' FROM hosts_templates ht'.
' WHERE '.dbConditionId('ht.hostid', array_keys($result))
));
if ($hosts_templates) {
// Select also template ID if not selected. It can be removed from results if not requested.
$template_options = $this->outputIsRequested('templateid', $options['selectParentTemplates'])
? $options['selectParentTemplates']
: array_merge($options['selectParentTemplates'], ['templateid']);
/*
* Since templates API does not have "link_type" field, remove it from request, so that template.get
* validation may pass successfully.
*/
if ($this->outputIsRequested('link_type', $template_options) && is_array($template_options)
&& ($key = array_search('link_type', $template_options)) !== false) {
unset($template_options[$key]);
}
$templates = API::Template()->get([
'output' => $template_options,
'templateids' => array_column($hosts_templates, 'templateid'),
'nopermissions' => $options['nopermissions'],
'preservekeys' => true
]);
if ($options['limitSelects'] !== null) {
order_result($templates, 'host');
}
}
/*
* In order to correctly slice the ordered templates in case of "limitSelects", first they must be
* mapped for each host. Otherwise incorrect results may appear. $relation_map key is the host ID, and
* values are template ID and, if selected, "link_type".
*/
$relation_map = [];
foreach ($hosts_templates as $host_template) {
if (!array_key_exists($host_template['hostid'], $relation_map)) {
$relation_map[$host_template['hostid']] = [];
}
$related_fields = ['templateid' => $host_template['templateid']];
if ($this->outputIsRequested('link_type', $options['selectParentTemplates'])) {
$related_fields['link_type'] = $host_template['link_type'];
}
$relation_map[$host_template['hostid']][] = $related_fields;
}
foreach ($result as $hostid => &$host) {
$host['parentTemplates'] = [];
if (array_key_exists($hostid, $relation_map)) {
$templateids = array_column($relation_map[$hostid], 'templateid');
$templateids = array_combine($templateids, $templateids);
// Find the matching templates and limit the results if necessary.
$host['parentTemplates'] = array_values(array_intersect_key($templates, $templateids));
if ($options['limitSelects'] !== null && $options['limitSelects'] != 0) {
$host['parentTemplates'] = array_slice($host['parentTemplates'], 0,
$options['limitSelects']
);
}
// Append the additional field from relation table.
if ($this->outputIsRequested('link_type', $options['selectParentTemplates'])) {
foreach ($host['parentTemplates'] as &$template) {
foreach ($relation_map[$hostid] as $rel_template) {
if (bccomp($template['templateid'], $rel_template['templateid']) == 0) {
$template['link_type'] = $rel_template['link_type'];
}
}
}
}
// Unset fields if they were not requested.
$host['parentTemplates'] = $this->unsetExtraFields($host['parentTemplates'], ['templateid'],
$options['selectParentTemplates']
);
}
}
unset($host);
}
else {
$templates = API::Template()->get([
'hostids' => $hostids,
'countOutput' => true,
'groupCount' => true
]);
$templates = zbx_toHash($templates, 'hostid');
foreach ($result as $hostid => $host) {
$result[$hostid]['parentTemplates'] = array_key_exists($hostid, $templates)
? $templates[$hostid]['rowscount']
: '0';
}
}
}
if ($options['selectItems'] !== null) {
if ($options['selectItems'] != API_OUTPUT_COUNT) {
$items = API::Item()->get([
'output' => $this->outputExtend($options['selectItems'], ['hostid', 'itemid']),
'hostids' => $hostids,
'nopermissions' => true,
'preservekeys' => true
]);
if (!is_null($options['limitSelects'])) {
order_result($items, 'name');
}
$relationMap = $this->createRelationMap($items, 'hostid', 'itemid');
$items = $this->unsetExtraFields($items, ['hostid', 'itemid'], $options['selectItems']);
$result = $relationMap->mapMany($result, $items, 'items', $options['limitSelects']);
}
else {
$items = API::Item()->get([
'hostids' => $hostids,
'nopermissions' => true,
'countOutput' => true,
'groupCount' => true
]);
$items = zbx_toHash($items, 'hostid');
foreach ($result as $hostid => $host) {
$result[$hostid]['items'] = array_key_exists($hostid, $items) ? $items[$hostid]['rowscount'] : '0';
}
}
}
if ($options['selectDiscoveries'] !== null) {
if ($options['selectDiscoveries'] != API_OUTPUT_COUNT) {
$items = API::DiscoveryRule()->get([
'output' => $this->outputExtend($options['selectDiscoveries'], ['hostid', 'itemid']),
'hostids' => $hostids,
'nopermissions' => true,
'preservekeys' => true
]);
if (!is_null($options['limitSelects'])) {
order_result($items, 'name');
}
$relationMap = $this->createRelationMap($items, 'hostid', 'itemid');
$items = $this->unsetExtraFields($items, ['hostid', 'itemid'], $options['selectDiscoveries']);
$result = $relationMap->mapMany($result, $items, 'discoveries', $options['limitSelects']);
}
else {
$items = API::DiscoveryRule()->get([
'hostids' => $hostids,
'nopermissions' => true,
'countOutput' => true,
'groupCount' => true
]);
$items = zbx_toHash($items, 'hostid');
foreach ($result as $hostid => $host) {
$result[$hostid]['discoveries'] = array_key_exists($hostid, $items)
? $items[$hostid]['rowscount']
: '0';
}
}
}
if ($options['selectTriggers'] !== null) {
if ($options['selectTriggers'] != API_OUTPUT_COUNT) {
$triggers = [];
$relationMap = new CRelationMap();
// discovered items
$res = DBselect(
'SELECT i.hostid,f.triggerid'.
' FROM items i,functions f'.
' WHERE '.dbConditionInt('i.hostid', $hostids).
' AND i.itemid=f.itemid'
);
while ($relation = DBfetch($res)) {
$relationMap->addRelation($relation['hostid'], $relation['triggerid']);
}
$related_ids = $relationMap->getRelatedIds();
if ($related_ids) {
$triggers = API::Trigger()->get([
'output' => $options['selectTriggers'],
'triggerids' => $related_ids,
'preservekeys' => true
]);
if (!is_null($options['limitSelects'])) {
order_result($triggers, 'description');
}
}
$result = $relationMap->mapMany($result, $triggers, 'triggers', $options['limitSelects']);
}
else {
$triggers = API::Trigger()->get([
'hostids' => $hostids,
'countOutput' => true,
'groupCount' => true
]);
$triggers = zbx_toHash($triggers, 'hostid');
foreach ($result as $hostid => $host) {
$result[$hostid]['triggers'] = array_key_exists($hostid, $triggers)
? $triggers[$hostid]['rowscount']
: '0';
}
}
}
if ($options['selectGraphs'] !== null) {
if ($options['selectGraphs'] != API_OUTPUT_COUNT) {
$graphs = [];
$relationMap = new CRelationMap();
// discovered items
$res = DBselect(
'SELECT i.hostid,gi.graphid'.
' FROM items i,graphs_items gi'.
' WHERE '.dbConditionInt('i.hostid', $hostids).
' AND i.itemid=gi.itemid'
);
while ($relation = DBfetch($res)) {
$relationMap->addRelation($relation['hostid'], $relation['graphid']);
}
$related_ids = $relationMap->getRelatedIds();
if ($related_ids) {
$graphs = API::Graph()->get([
'output' => $options['selectGraphs'],
'graphids' => $related_ids,
'preservekeys' => true
]);
if (!is_null($options['limitSelects'])) {
order_result($graphs, 'name');
}
}
$result = $relationMap->mapMany($result, $graphs, 'graphs', $options['limitSelects']);
}
else {
$graphs = API::Graph()->get([
'hostids' => $hostids,
'countOutput' => true,
'groupCount' => true
]);
$graphs = zbx_toHash($graphs, 'hostid');
foreach ($result as $hostid => $host) {
$result[$hostid]['graphs'] = array_key_exists($hostid, $graphs)
? $graphs[$hostid]['rowscount']
: '0';
}
}
}
if ($options['selectHttpTests'] !== null) {
if ($options['selectHttpTests'] != API_OUTPUT_COUNT) {
$httpTests = API::HttpTest()->get([
'output' => $this->outputExtend($options['selectHttpTests'], ['hostid', 'httptestid']),
'hostids' => $hostids,
'nopermissions' => true,
'preservekeys' => true
]);
if (!is_null($options['limitSelects'])) {
order_result($httpTests, 'name');
}
$relationMap = $this->createRelationMap($httpTests, 'hostid', 'httptestid');
$httpTests = $this->unsetExtraFields($httpTests, ['hostid', 'httptestid'], $options['selectHttpTests']);
$result = $relationMap->mapMany($result, $httpTests, 'httpTests', $options['limitSelects']);
}
else {
$httpTests = API::HttpTest()->get([
'hostids' => $hostids,
'nopermissions' => true,
'countOutput' => true,
'groupCount' => true
]);
$httpTests = zbx_toHash($httpTests, 'hostid');
foreach ($result as $hostid => $host) {
$result[$hostid]['httpTests'] = array_key_exists($hostid, $httpTests)
? $httpTests[$hostid]['rowscount']
: '0';
}
}
}
if ($options['selectValueMaps'] !== null) {
if ($options['selectValueMaps'] === API_OUTPUT_EXTEND) {
$options['selectValueMaps'] = ['valuemapid', 'name', 'mappings'];
}
foreach ($result as &$host) {
$host['valuemaps'] = [];
}
unset($host);
$valuemaps = DB::select('valuemap', [
'output' => array_diff($this->outputExtend($options['selectValueMaps'], ['valuemapid', 'hostid']),
['mappings']
),
'filter' => ['hostid' => $hostids],
'preservekeys' => true
]);
if ($this->outputIsRequested('mappings', $options['selectValueMaps']) && $valuemaps) {
$params = [
'output' => ['valuemapid', 'type', 'value', 'newvalue'],
'filter' => ['valuemapid' => array_keys($valuemaps)],
'sortfield' => ['sortorder']
];
$query = DBselect(DB::makeSql('valuemap_mapping', $params));
while ($mapping = DBfetch($query)) {
$valuemaps[$mapping['valuemapid']]['mappings'][] = [
'type' => $mapping['type'],
'value' => $mapping['value'],
'newvalue' => $mapping['newvalue']
];
}
}
foreach ($valuemaps as $valuemap) {
$result[$valuemap['hostid']]['valuemaps'][] = array_intersect_key($valuemap,
array_flip($options['selectValueMaps'])
);
}
}
return $result;
}
/**
* Add the existing host or template groups, templates, tags, macros.
*
* @param array $hosts
* @param array $db_hosts
*/
protected function addAffectedObjects(array $hosts, array &$db_hosts): void {
$this->addAffectedGroups($hosts, $db_hosts);
parent::addAffectedObjects($hosts, $db_hosts);
}
/**
* @param array $hosts
* @param array $db_hosts
*/
protected function addAffectedGroups(array $hosts, array &$db_hosts): void {
$id_field_name = $this instanceof CTemplate ? 'templateid' : 'hostid';
$hostids = [];
foreach ($hosts as $host) {
if (array_key_exists('groups', $host)) {
$hostids[] = $host[$id_field_name];
$db_hosts[$host[$id_field_name]]['groups'] = [];
}
}
if (!$hostids) {
return;
}
$filter = ['hostid' => $hostids];
if (self::$userData['type'] == USER_TYPE_ZABBIX_ADMIN) {
if ($this instanceof CTemplate) {
$db_groups = API::TemplateGroup()->get([
'output' => [],
'templateids' => $hostids,
'preservekeys' => true
]);
}
else {
$db_groups = API::HostGroup()->get([
'output' => [],
'hostids' => $hostids,
'preservekeys' => true
]);
}
$filter += ['groupid' => array_keys($db_groups)];
}
$options = [
'output' => ['hostgroupid', 'hostid', 'groupid'],
'filter' => $filter
];
$db_groups = DBselect(DB::makeSql('hosts_groups', $options));
while ($db_group = DBfetch($db_groups)) {
$db_hosts[$db_group['hostid']]['groups'][$db_group['hostgroupid']] =
array_diff_key($db_group, array_flip(['hostid']));
}
}
/**
* Add the existing groups, macros or templates whether these are affected by the mass methods.
*
* @param string $objects
* @param array $objectids
* @param array $db_hosts
*/
protected function massAddAffectedObjects(string $objects, array $objectids, array &$db_hosts): void {
$id_field_name = $this instanceof CTemplate ? 'templateid' : 'hostid';
foreach ($db_hosts as &$db_host) {
$db_host[$objects] = [];
}
unset($db_host);
if ($objects === 'groups') {
$filter = ['hostid' => array_keys($db_hosts)];
if ($objectids) {
$filter += ['groupid' => $objectids];
}
elseif (self::$userData['type'] == USER_TYPE_ZABBIX_ADMIN) {
if ($this instanceof CTemplate) {
$db_groups = API::TemplateGroup()->get([
'output' => [],
'templateids' => array_keys($db_hosts),
'preservekeys' => true
]);
}
else {
$db_groups = API::HostGroup()->get([
'output' => [],
'hostids' => array_keys($db_hosts),
'preservekeys' => true
]);
}
$filter += ['groupid' => array_keys($db_groups)];
}
$options = [
'output' => ['hostgroupid', 'hostid', 'groupid'],
'filter' => $filter
];
$db_hosts_groups = DBselect(DB::makeSql('hosts_groups', $options));
while ($link = DBfetch($db_hosts_groups)) {
$db_hosts[$link['hostid']]['groups'][$link['hostgroupid']] =
array_diff_key($link, array_flip(['hostid']));
}
}
if ($objects === 'macros') {
$options = [
'output' => ['hostmacroid', 'hostid', 'macro', 'value', 'description', 'type'],
'filter' => ['hostid' => array_keys($db_hosts)]
];
if ($objectids) {
$macro_patterns = [];
$trimmed_macros = [];
foreach ($objectids as $macro) {
$trimmed_macro = CApiInputValidator::trimMacro($macro);
$context_pos = strpos($trimmed_macro, ':');
$macro_patterns[] = ($context_pos === false)
? '{$'.$trimmed_macro
: '{$'.substr($trimmed_macro, 0, $context_pos);
$trimmed_macros[] = $trimmed_macro;
}
$options += [
'search' => ['macro' => $macro_patterns],
'startSearch' => true,
'searchByAny' => true
];
}
$db_macros = DBselect(DB::makeSql('hostmacro', $options));
while ($db_macro = DBfetch($db_macros)) {
if (!$objectids || in_array(CApiInputValidator::trimMacro($db_macro['macro']), $trimmed_macros)) {
$db_hosts[$db_macro['hostid']]['macros'][$db_macro['hostmacroid']] =
array_diff_key($db_macro, array_flip(['hostid']));
}
}
}
if ($objects === 'templates') {
$permitted_templates = [];
if (!$objectids && self::$userData['type'] == USER_TYPE_ZABBIX_ADMIN) {
$permitted_templates = API::Template()->get([
'output' => [],
'hostids' => array_keys($db_hosts),
'preservekeys' => true
]);
}
$options = [
'output' => ['hosttemplateid', 'hostid', 'templateid'],
'filter' => [
'hostid' => array_keys($db_hosts)
]
];
$db_hosts_templates = DBselect(DB::makeSql('hosts_templates', $options));
while ($link = DBfetch($db_hosts_templates)) {
if ($objectids) {
if (in_array($link['templateid'], $objectids)) {
$db_hosts[$link['hostid']]['templates'][$link['hosttemplateid']] =
array_diff_key($link, array_flip(['hostid']));
}
else {
$db_hosts[$link['hostid']]['nopermissions_templates'][$link['hosttemplateid']] =
array_diff_key($link, array_flip(['hostid']));
}
}
else {
if (self::$userData['type'] == USER_TYPE_SUPER_ADMIN
|| array_key_exists($link['templateid'], $permitted_templates)) {
$db_hosts[$link['hostid']]['templates'][$link['hosttemplateid']] =
array_diff_key($link, array_flip(['hostid']));
}
else {
$db_hosts[$link['hostid']]['nopermissions_templates'][$link['hosttemplateid']] =
array_diff_key($link, array_flip(['hostid']));
}
}
}
}
}
/**
* Get templates or hosts input array based on requested data and database data.
*
* @param array $data
* @param array $db_objects
*
* @return array
*/
protected function getObjectsByData(array $data, array $db_objects): array {
$id_field_name = $this instanceof CTemplate ? 'templateid' : 'hostid';
$objects = [];
foreach ($db_objects as $db_object) {
$object = [$id_field_name => $db_object[$id_field_name]];
if (array_key_exists('groups', $db_object)) {
$object['groups'] = [];
if (array_key_exists('groups', $data)) {
foreach ($data['groups'] as $group) {
$object['groups'][] = ['groupid' => $group['groupid']];
}
}
}
if (array_key_exists('macros', $db_object)) {
$object['macros'] = [];
if (array_key_exists('macros', $data) && is_array(reset($data['macros']))) {
$db_macros = [];
foreach ($db_object['macros'] as $db_macro) {
$db_macros[CApiInputValidator::trimMacro($db_macro['macro'])] = $db_macro;
}
foreach ($data['macros'] as $macro) {
$trimmed_macro = CApiInputValidator::trimMacro($macro['macro']);
if (array_key_exists($trimmed_macro, $db_macros)) {
$object['macros'][] = ['hostmacroid' => $db_macros[$trimmed_macro]['hostmacroid']] + $macro
+ ['description' => DB::getDefault('hostmacro', 'description')];
}
else {
$object['macros'][] = $macro;
}
}
}
}
if (array_key_exists('templates', $db_object)) {
$templates = $this instanceof CTemplate ? 'templates_link' : 'templates';
$templateids = $this instanceof CTemplate ? 'templateids_link' : 'templateids';
if (array_key_exists($templates, $data) || array_key_exists($templateids, $data)) {
$object['templates'] = [];
if (array_key_exists($templates, $data)) {
foreach ($data[$templates] as $template) {
$object['templates'][] = ['templateid' => $template['templateid']];
}
}
}
if (array_key_exists('templates_clear', $data) || array_key_exists('templateids_clear', $data)) {
$object['templates_clear'] = [];
$db_templateids = array_column($db_object['templates'], 'templateid');
if (array_key_exists('templates_clear', $data)) {
foreach ($data['templates_clear'] as $template) {
if (in_array($template['templateid'], $db_templateids)) {
$object['templates_clear'][] = ['templateid' => $template['templateid']];
}
}
}
else {
foreach ($data['templateids_clear'] as $templateid) {
if (in_array($templateid, $db_templateids)) {
$object['templates_clear'][] = ['templateid' => $templateid];
}
}
}
}
}
$objects[] = $object;
}
return $objects;
}
}