<?php /* ** Zabbix ** Copyright (C) 2001-2024 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 'vendor/autoload.php'; require_once dirname(__FILE__).'/../../../include/defines.inc.php'; require_once dirname(__FILE__).'/../../../include/hosts.inc.php'; require_once dirname(__FILE__).'/../../../include/db.inc.php'; class CDataHelper extends CAPIHelper { protected static $data = null; protected static $request = []; protected static $response = []; private static $objectids = []; private static $detachedids = []; /** * Prepare request for API call and make API call (@see callRaw). * * @param string $method API method to be called. * @param mixed $params API call params. * * @return array * * @throws Exception on API error */ public static function call($method, $params) { global $URL; if (!$URL) { $URL = PHPUNIT_URL.'api_jsonrpc.php'; } static::$request = []; static::$response = []; if (CAPIHelper::getSessionId() === null) { CAPIHelper::createSessionId(); } $response = CAPIHelper::call($method, $params); if (array_key_exists('error', $response)) { throw new Exception($method.' API call failed: '. json_encode($params, JSON_PRETTY_PRINT)."\n". json_encode($response['error'], JSON_PRETTY_PRINT) ); } if (!array_key_exists('result', $response)) { throw new Exception('API call failed: result is not present'); } static::$request = (CTestArrayHelper::isAssociative($params)) ? [$params] : $params; static::$response = $response['result']; return static::$response; } /** * Prepare request for API call and make API call (@see callRaw). * * @param string $method API method to be called. * @param mixed $params API call params. * * @return array * * @throws Exception on API error */ public static function getIds($field) { $ids = []; $result = reset(static::$response); if (count(static::$request) !== count($result)) { throw new Exception('Failed to get ids: record counts don\'t match'); } foreach (static::$request as $i => $object) { if (!array_key_exists($field, $object)) { throw new Exception('Failed to get ids: field "'.$field.'" is not present in request.'); } if (!array_key_exists($i, $result)) { throw new Exception('Failed to get ids: element ('.$i.') is not present in result.'); } if (array_key_exists($object[$field], $ids)) { throw new Exception('Failed to get ids: field "'.$field.'" is not unique.'); } $ids[$object[$field]] = $result[$i]; } return $ids; } /** * Load the data source data from the file cache. */ protected static function preload() { if (static::$data === null) { static::$data = []; if (!defined('PHPUNIT_DATA_DIR')) { return; } foreach (new DirectoryIterator(PHPUNIT_DATA_DIR) as $file) { if ($file->isDot() || $file->isDir() || strtolower($file->getExtension()) !== 'json') { continue; } $name = $file->getBasename('.'.$file->getExtension()); static::$data[$name] = json_decode(file_get_contents($file->getPathname()), true); } } } /** * Get data from the data sources. * * @param mixed $path data path to look for * @param mixed $default default value to be returned if data doesn't exist * * @return mixed */ public static function get($path, $default = null) { return CTestArrayHelper::get(static::$data, $path, $default); } /** * Load specific data source data. * * @param mixed $source name of the data source(s) * * @return boolean * * @throws \Exception */ public static function load($source) { if (is_array($source)) { $result = true; foreach ($source as $name) { if (!static::load($name)) { $result = false; } } return $result; } static::preload(); if (array_key_exists($source, static::$data)) { return true; } try { $path = PHPUNIT_DATA_SOURCES_DIR.$source.'.php'; if (!file_exists($path)) { throw new \Exception('File "'.$path.'" doesn\'t exist.'); } require_once $path; static::$data[$source] = forward_static_call([$source, 'load']); if (defined('PHPUNIT_DATA_DIR')) { $data = json_encode(static::get($source)); file_put_contents(PHPUNIT_DATA_DIR.$source.'.json', $data); } } catch (\Exception $e) { echo 'Failed to load data from data source "'.$source.'".'."\n\n".$e->getMessage()."\n".$e->getTraceAsString(); return false; } return true; } /** * Add data to item. * * @param string $itemid item id * @param array $values value that should be sent to item * @param mixed $time time when value was received */ public static function addItemData($itemid, $values, $time = null) { self::convertValueReference($itemid); if (!is_array($values)) { $values = [$values]; } if ($time === null) { if (is_array($values)) { $offset = time(); $time = []; for ($i = count($values); $i > 0; $i--) { $time[] = $offset - $i; } } else { $time = time(); } } elseif (is_array($time)) { if (count($time) !== count($values)) { throw new Exception('Value count should match the time record count.'); } $time = array_values($time); } // Set correct history table where to insert data. $suffix = static::getItemDataTableSuffix($itemid); foreach (array_values($values) as $key => $value) { $clock = is_array($time) ? $time[$key] : $time; // If value is an array, it means that we are dealing with trend data, which is inserted in differently. if (is_array($value)) { DBexecute('INSERT INTO trends'.$suffix.' (itemid, clock, num, value_min, value_avg,'. ' value_max) VALUES ('.zbx_dbstr($itemid).', '.zbx_dbstr($clock).', '.zbx_dbstr($value['num']). ', '.zbx_dbstr($value['min']).', '.zbx_dbstr($value['avg']).', '.zbx_dbstr($value['max']).')' ); } else { DBexecute('INSERT INTO history'.$suffix.' (itemid, clock, value) VALUES ('.zbx_dbstr($itemid). ', '.zbx_dbstr($clock).', '.zbx_dbstr($value).')' ); } } } /** * Remove item data from history and trends tables. * * @param string|array $itemids item id(s) */ public static function removeItemData($itemids) { $groups = []; if (!is_array($itemids)) { $itemids = [$itemids]; } foreach ($itemids as $itemid) { $groups[self::getItemDataTableSuffix($itemid)][] = zbx_dbstr($itemid); } foreach (array_keys($groups) as $suffix) { DBexecute('DELETE FROM history'.$suffix.' WHERE itemid IN ('.implode(',', $groups[$suffix]).')'); if ($suffix === '_uint' || $suffix === '') { DBexecute('DELETE FROM trends'.$suffix.' WHERE itemid IN ('.implode(',', $groups[$suffix]).')'); } } } /** * Get history data table. * * @param string $itemid item id */ public static function getItemDataTableSuffix($itemid) { // Check item value type to set correct history table. $value_type = CDBHelper::getValue('SELECT value_type FROM items where itemid='.zbx_dbstr($itemid)); $suffixes = ['', '_str', '_log', '_uint', '_text']; if (!array_key_exists($value_type, $suffixes)) { throw new Exception('Unsupported item value type: '.$value_type); } return $suffixes[$value_type]; } /** * Create objects using API. * Usually only the object's "name/key" need to be provided. Some defaults (e.g. item's type, value_type) are mixed * in and the "parent ID" property (e.g. host's groupid, item's hostid, etc.), if not specified, inferred by using * the last known such object's ID. Previously defined objects can be linked by their reference ID, f.e.: * `'master_itemid' => ':item:key.of.master.item'`. * * Call CDataHelper::cleanUp() to delete objects defined here along with child objects created during the test. * * @param array $objects */ public static function createObjects(array $objects): void { $object_types = array_fill_keys(['template_groups', 'host_groups', 'templates', 'proxies', 'hosts', 'triggers', 'roles', 'user_groups', 'users', 'scripts', 'drules', 'actions', 'graphs', 'dashboards', 'services', 'maintenances', 'correlations', 'slas', 'reports' ], []); if (array_diff_key($objects, $object_types)) { throw new Exception('Unsupported object types for data helper: '. implode(', ', array_keys(array_diff_key($objects, $object_types))) ); } $objects += $object_types; try { self::createTemplateGroups($objects['template_groups']); self::createHostGroups($objects['host_groups']); self::createTemplates($objects['templates']); self::createProxies($objects['proxies']); self::createHosts($objects['hosts']); self::createTriggers($objects['triggers']); self::createRoles($objects['roles']); self::createUserGroups($objects['user_groups']); self::createUsers($objects['users']); self::createScripts($objects['scripts']); self::createDrules($objects['drules']); self::createActions($objects['actions']); self::createGraphs($objects['graphs']); self::createDashboards($objects['dashboards']); self::createServices($objects['services']); self::createMaintenances($objects['maintenances']); self::createCorrelations($objects['correlations']); self::createSlas($objects['slas']); self::createReports($objects['reports']); } catch (Exception $e) { self::cleanUp(); throw new Exception($e->getMessage()."\n".$e->getFile().':'.$e->getLine(), 0, $e); } } /** * @param array $template_groups */ private static function createTemplateGroups(array $template_groups): void { if (!$template_groups) { return; } $result = ZABBIX_VERSION < 6.4 ? self::call('hostgroup.create', $template_groups) : self::call('templategroup.create', $template_groups); foreach ($template_groups as $template_group) { self::$objectids['template_group'][$template_group['name']] = array_shift($result['groupids']); } } /** * @param array $host_groups */ private static function createHostGroups(array $host_groups): void { if (!$host_groups) { return; } $result = self::call('hostgroup.create', $host_groups); foreach ($host_groups as $host_group) { self::$objectids['host_group'][$host_group['name']] = array_shift($result['groupids']); } } /** * @param array $templates * * @return array */ public static function createTemplates(array $templates): array { if (!$templates) { return []; } $value_maps = []; $items = []; $lld_rules = []; $dashboards = []; $httptests = []; foreach ($templates as $i => &$template) { $template += array_key_exists('template_group', self::$objectids) ? [ 'groups' => [ ['groupid' => end(self::$objectids['template_group'])] ] ] : []; $parent_hostid = ['hostid' => array_key_exists('templateid', $template) ? $template['templateid'] : ':template:'.$template['host'] ]; if (array_key_exists('value_maps', $template)) { foreach ($template['value_maps'] as $value_map) { $value_maps[] = $value_map + $parent_hostid; } unset($template['value_maps']); } if (array_key_exists('items', $template)) { foreach ($template['items'] as $item) { $items[] = $item + $parent_hostid; } unset($template['items']); } if (array_key_exists('discoveryrules', $template)) { $template['lld_rules'] = $template['discoveryrules']; unset($template['discoveryrules']); } if (array_key_exists('lld_rules', $template)) { foreach ($template['lld_rules'] as $lld_rule) { $lld_rules[] = $lld_rule + $parent_hostid; } unset($template['lld_rules']); } if (array_key_exists('httptests', $template)) { foreach ($template['httptests'] as $httptest) { $httptests[] = $httptest + $parent_hostid; } unset($template['httptests']); } if (array_key_exists('dashboards', $template)) { foreach ($template['dashboards'] as $dashboard) { $dashboards[] = $dashboard + ['templateid' => $parent_hostid['hostid']]; } unset($template['dashboards']); } if (array_key_exists('templateid', $template)) { unset($templates[$i]); } } unset($template); if ($templates) { self::convertTemplateReferences($templates); $result = self::call('template.create', $templates); foreach ($templates as &$template) { $templateid = array_shift($result['templateids']); self::$objectids['template'][$template['host']] = $templateid; $template['templateid'] = $templateid; } unset($template); } self::createValueMaps($value_maps); self::createItems($items); self::createLldRules($lld_rules); self::createHttptests($httptests); self::createTemplateDashboards($dashboards); if (!$templates) { self::$detachedids += array_fill_keys(['value_map', 'item', 'lld_rule', 'httptest', 'template_dashboard'], []); self::$detachedids['value_map'] = array_merge(self::$detachedids['value_map'], array_column($value_maps, 'valuemapid')); self::$detachedids['item']= array_merge(self::$detachedids['item'], array_column($items, 'itemid')); self::$detachedids['lld_rule'] = array_merge(self::$detachedids['lld_rule'], array_column($lld_rules, 'itemid')); self::$detachedids['httptest'] = array_merge(self::$detachedids['httptest'], array_column($httptests, 'httptestid')); self::$detachedids['template_dashboard'] = array_merge(self::$detachedids['template_dashboard'], array_column($dashboards, 'dashboardid')); self::$detachedids = array_filter(self::$detachedids); } return $templates ? [ 'templateids' => array_column($templates, 'templateid', 'host'), 'itemids' => self::extractItemMap($items, $templates, 'templateid'), 'discoveryruleids' => self::extractItemMap($lld_rules, $templates, 'templateid') ] : []; } public static function convertTemplateReferences(array &$templates): void { self::convertPropertyReference($templates, 'templateid'); self::convertPropertyReference($templates, 'groups.groupid'); self::convertPropertyReference($templates, 'templates.templateid'); } private static function createProxies(array $proxies): void { if (!$proxies) { return; } foreach ($proxies as &$proxy) { $proxy = self::prepareProxy($proxy); } unset($proxy); $result = self::call('proxy.create', $proxies); foreach ($proxies as $proxy) { ZABBIX_VERSION < 7 ? self::$objectids['proxy'][$proxy['host']] = array_shift($result['proxyids']) : self::$objectids['proxy'][$proxy['name']] = array_shift($result['proxyids']); } } /** * @param array $proxy * * @return array */ public static function prepareProxy(array $proxy): array { return $proxy + ['status' => HOST_STATUS_PROXY_PASSIVE]; } /** * Create hosts with nested objects. * * @param array $hosts API call parameters. * In addition to the default host.create params, f.e., "items" and "lld_rules" can be set * for any of the host in order to create the related objects. * * @return array */ public static function createHosts(array $hosts): array { if (!$hosts) { return []; } $value_maps = []; $items = []; $lld_rules = []; $httptests = []; $hostids = []; foreach ($hosts as $i => &$host) { $host += array_key_exists('host_group', self::$objectids) ? [ 'groups' => [ ['groupid' => end(self::$objectids['host_group'])] ] ] : []; $parent_hostid = ['hostid' => array_key_exists('hostid', $host) ? $host['hostid'] : ':host:'.$host['host']]; $hostids[] = $parent_hostid['hostid']; if (array_key_exists('value_maps', $host)) { foreach ($host['value_maps'] as $value_map) { $value_maps[] = $value_map + $parent_hostid; } unset($host['value_maps']); } if (array_key_exists('items', $host)) { foreach ($host['items'] as $item) { $items[] = $item + $parent_hostid; } unset($host['items']); } if (array_key_exists('discoveryrules', $host)) { $host['lld_rules'] = $host['discoveryrules']; unset($host['discoveryrules']); } if (array_key_exists('lld_rules', $host)) { foreach ($host['lld_rules'] as $lld_rule) { $lld_rules[] = $lld_rule + $parent_hostid; } unset($host['lld_rules']); } if (array_key_exists('httptests', $host)) { foreach ($host['httptests'] as $httptest) { $httptests[] = $httptest + $parent_hostid; } unset($host['httptests']); } if (array_key_exists('hostid', $host)) { unset($hosts[$i]); } } unset($host); if ($hosts) { self::convertHostReferences($hosts); $result = self::call('host.create', $hosts); foreach ($hosts as &$host) { $hostid = array_shift($result['hostids']); self::$objectids['host'][$host['host']] = $hostid; $host['hostid'] = $hostid; } unset($host); } if ($items || $lld_rules) { self::convertValueReferences($hostids); $interfaces = static::getInterfaces(array_unique($hostids)); self::assignInterfaces($items, $interfaces); self::assignInterfaces($lld_rules, $interfaces); } self::createValueMaps($value_maps); self::createItems($items); self::createLldRules($lld_rules); self::createHttptests($httptests); if (!$hosts) { self::$detachedids += array_fill_keys(['value_map', 'item', 'lld_rule', 'httptest'], []); self::$detachedids['value_map'] = array_merge(self::$detachedids['value_map'], array_column($value_maps, 'valuemapid')); self::$detachedids['item']= array_merge(self::$detachedids['item'], array_column($items, 'itemid')); self::$detachedids['lld_rule'] = array_merge(self::$detachedids['lld_rule'], array_column($lld_rules, 'itemid')); self::$detachedids['httptest'] = array_merge(self::$detachedids['httptest'], array_column($httptests, 'httptestid')); self::$detachedids = array_filter(self::$detachedids); } return $hosts ? [ 'hostids' => array_column($hosts, 'hostid', 'host'), 'itemids' => self::extractItemMap($items, $hosts, 'hostid'), 'discoveryruleids' => self::extractItemMap($lld_rules, $hosts, 'hostid') ] : []; } public static function convertHostReferences(array &$hosts): void { self::convertPropertyReference($hosts, 'hostid'); self::convertPropertyReference($hosts, 'groups.groupid'); self::convertPropertyReference($hosts, 'templates.templateid'); ZABBIX_VERSION < 7 ? self::convertPropertyReference($hosts, 'proxy_hostid') : self::convertPropertyReference($hosts, 'proxyid'); } /** * Get host interfaces. * * @param array $hostids * * @return array */ public static function getInterfaces(array $hostids): array { $result = [ 'default_interfaces' => [], 'ids' => [] ]; $hosts = static::call('host.get', [ 'output' => ['hostid'], 'hostids' => array_values($hostids), 'selectInterfaces' => ['interfaceid', 'useip', 'ip', 'type', 'dns', 'port', 'main'] ]); foreach ($hosts as $host) { foreach ($host['interfaces'] as $interface) { if ($interface['main'] == INTERFACE_PRIMARY) { $result['default_interfaces'][$host['hostid']][$interface['type']] = $interface['interfaceid']; } $address = $interface['useip'] == INTERFACE_USE_IP ? $interface['ip'] : $interface['dns']; $result['ids'][$host['hostid']][$address.':'.$interface['port']] = $interface['interfaceid']; } } return $result; } private static function assignInterfaces(array &$items, array $interfaces): void { $item_type_interfaces = [ ITEM_TYPE_SNMP => INTERFACE_TYPE_SNMP, ITEM_TYPE_SNMPTRAP => INTERFACE_TYPE_SNMP, ITEM_TYPE_IPMI => INTERFACE_TYPE_IPMI, ITEM_TYPE_ZABBIX => INTERFACE_TYPE_AGENT, ITEM_TYPE_SIMPLE => INTERFACE_TYPE_ANY, ITEM_TYPE_EXTERNAL => INTERFACE_TYPE_ANY, ITEM_TYPE_SSH => INTERFACE_TYPE_ANY, ITEM_TYPE_TELNET => INTERFACE_TYPE_ANY, ITEM_TYPE_JMX => INTERFACE_TYPE_JMX, ITEM_TYPE_HTTPAGENT => INTERFACE_TYPE_OPT ]; foreach ($items as &$item) { if (array_key_exists('interfaceid', $item) || !array_key_exists($item['type'], $item_type_interfaces)) { continue; } $interface_type = $item_type_interfaces[$item['type']]; $hostid = self::getConvertedValueReference($item['hostid']); if (array_key_exists($hostid, $interfaces['default_interfaces'])) { if ($interface_type !== null && array_key_exists($interface_type, $interfaces['default_interfaces'][$hostid])) { $item['interfaceid'] = $interfaces['default_interfaces'][$hostid][$interface_type]; } } if (array_key_exists($hostid, $interfaces['ids'])) { $interface = CTestArrayHelper::get($item, 'interface'); unset($item['interface']); if ($interface !== null && array_key_exists($interfaces['ids'][$hostid], $interface)) { $item['interfaceid'] = $interfaces['ids'][$hostid][$interface]; } } } unset($item); } private static function extractItemMap(array $items, array $hosts, string $id_field_name): array { $result = []; $hosts = array_column($hosts, null, $id_field_name); foreach ($items as $item) { $result[$hosts[$item['hostid']]['host'].':'.$item['key_']] = $item['itemid']; } return $result; } /** * @param array $value_maps */ private static function createValueMaps(array &$value_maps): void { if (!$value_maps) { return; } self::convertValueMapReferences($value_maps); $result = self::call('valuemap.create', $value_maps); foreach ($value_maps as &$value_map) { $value_map['valuemapid'] = array_shift($result['valuemapids']); self::$objectids['value_map'][$value_map['name']] = $value_map['valuemapid']; } unset($value_map); } public static function convertValueMapReferences(array &$value_maps): void { self::convertPropertyReference($value_maps, 'valuemapid'); self::convertPropertyReference($value_maps, 'hostid'); } /** * @param array $items * * @return array */ private static function createItems(array &$items): void { if (!$items) { return; } $host_refs = []; $item_indexes = []; foreach ($items as $i => &$item) { $host_refs[$i] = $item['hostid']; $item = self::prepareItem($item); $item_indexes[$item['hostid']][':item:'.$item['key_']] = $i; } unset($item); $dep_items = []; foreach ($items as $i => $item) { if ($item['type'] == ITEM_TYPE_DEPENDENT) { if (!array_key_exists($item['hostid'], $item_indexes) || !array_key_exists($item['master_itemid'], $item_indexes[$item['hostid']])) { throw new Exception(sprintf('Wrong master item ID for item with key "%1$s" on "%2$s".', $item['key_'], $host_refs[$i] )); } $dep_items[$item_indexes[$item['hostid']][$item['master_itemid']]][$i] = $item; unset($items[$i]); } } $result_items = []; do { self::convertItemReferences($items); $result = self::call('item.create', array_values($items)); $_items = []; foreach ($items as $i => &$item) { $item['itemid'] = array_shift($result['itemids']); self::$objectids['item'][$item['key_']][$host_refs[$i]] = $item['itemid']; if (array_key_exists($i, $dep_items)) { $_items += $dep_items[$i]; } } unset($item); $result_items += $items; } while ($items = $_items); $items = $result_items; } /** * @param array $item * * @return array */ public static function prepareItem(array $item): array { return $item + [ 'name' => $item['key_'], 'type' => array_key_exists('master_itemid', $item) ? ITEM_TYPE_DEPENDENT : ITEM_TYPE_TRAPPER, 'value_type' => ITEM_VALUE_TYPE_STR ]; } public static function convertItemReferences(array &$items): void { self::convertPropertyReference($items, 'itemid'); self::convertPropertyReference($items, 'hostid'); self::convertPropertyReference($items, 'valuemapid'); self::convertPropertyReference($items, 'interfaceid'); self::convertPropertyReference($items, 'master_itemid'); } /** * @param array $item * @param int $from * @param int $to * * @return array * * @throws Exception */ public static function prepareItemSet(array $item, int $from, int $to): array { if ($from > $to) { throw new Exception('Incorrect range parameters.'); } $bracket_pos = strpos($item['key_'], '['); $items = []; for ($i = $from; $i <= $to; $i++) { $key_ = $bracket_pos === false ? $item['key_'].'.'.$i : substr_replace($item['key_'], '.'.$i, $bracket_pos, 0); $items[] = self::prepareItem(['key_' => $key_] + $item); } return $items; } private static function createLldRules(array &$lld_rules): void { if (!$lld_rules) { return; } $host_refs = []; $item_prototypes = []; $host_prototypes = []; $trigger_prototypes = []; $graph_prototypes = []; foreach ($lld_rules as $i => &$lld_rule) { $host_refs[$i] = $lld_rule['hostid']; $parent_ruleid = array_key_exists('itemid', $lld_rule) ? ['ruleid' => $lld_rule['itemid']] : ['ruleid' => ':lld_rule:'.$lld_rule['key_'].($lld_rule['hostid'][0] === ':' ? $host_refs[$i] : '')]; $lld_rule = self::prepareLldRule($lld_rule); if (array_key_exists('item_prototypes', $lld_rule)) { foreach ($lld_rule['item_prototypes'] as $item_prototype) { if (array_key_exists('item_prototype', self::$objectids) && array_key_exists($item_prototype['key_'], self::$objectids['item_prototype'])) { throw new Exception('Non-unique graph prototype alias: '.$item_prototype['key_']); } $item_prototypes[] = $item_prototype + ['hostid' => $host_refs[$i]] + $parent_ruleid; } unset($lld_rule['item_prototypes']); } if (array_key_exists('host_prototypes', $lld_rule)) { foreach ($lld_rule['host_prototypes'] as $host_prototype) { $host_prototypes[] = $host_prototype + $parent_ruleid; } unset($lld_rule['host_prototypes']); } if (array_key_exists('trigger_prototypes', $lld_rule)) { foreach ($lld_rule['trigger_prototypes'] as $alias => $trigger_prototype) { if (is_numeric($alias)) { throw new Exception('Trigger prototypes must use aliases as indexes: '. json_encode($trigger_prototype) ); } elseif (array_key_exists('trigger_prototype', self::$objectids) && array_key_exists($alias, self::$objectids['trigger_prototype'])) { throw new Exception('Non-unique trigger prototype alias: '.$alias); } } $trigger_prototypes += $lld_rule['trigger_prototypes']; unset($lld_rule['trigger_prototypes']); } if (array_key_exists('graph_prototypes', $lld_rule)) { foreach ($lld_rule['graph_prototypes'] as $alias => $graph_prototype) { if (is_numeric($alias)) { throw new Exception('Graph prototypes must use aliases as indexes: '. json_encode($graph_prototype) ); } elseif (array_key_exists('graph_prototype', self::$objectids) && array_key_exists($alias, self::$objectids['graph_prototype'])) { throw new Exception('Non-unique graph prototype alias: '.$alias); } $graph_prototypes += $lld_rule['graph_prototypes']; } unset($lld_rule['graph_prototypes']); } if (array_key_exists('itemid', $lld_rule)) { unset($lld_rules[$i]); } } unset($lld_rule); if ($lld_rules) { self::convertLldRuleReferences($lld_rules); $result = self::call('discoveryrule.create', $lld_rules); foreach ($lld_rules as $i => &$lld_rule) { $lld_rule['itemid'] = array_shift($result['itemids']); self::$objectids['lld_rule'][$lld_rule['key_']][$host_refs[$i]] = $lld_rule['itemid']; } unset($lld_rule); } self::createItemPrototypes($item_prototypes); self::createHostPrototypes($host_prototypes); self::createTriggerPrototypes($trigger_prototypes); self::createGraphPrototypes($graph_prototypes); if (!$lld_rules) { self::$detachedids += array_fill_keys(['item_prototype', 'host_prototype', 'trigger_prototype', 'graph_prototype'], [] ); self::$detachedids['item_prototype'] = array_merge(self::$detachedids['item_prototype'], array_column($item_prototypes, 'itemid')); self::$detachedids['host_prototype'] = array_merge(self::$detachedids['host_prototype'], array_column($host_prototypes, 'hostid')); self::$detachedids['trigger_prototype'] = array_merge(self::$detachedids['trigger_prototype'], array_column($trigger_prototypes, 'triggerid')); self::$detachedids['graph_prototype'] = array_merge(self::$detachedids['graph_prototype'], array_column($graph_prototypes, 'graphid')); self::$detachedids = array_filter(self::$detachedids); } } /** * @param array $lld_rule * * @return array */ public static function prepareLldRule(array $lld_rule): array { return $lld_rule + (array_key_exists('key_', $lld_rule) ? ['name' => $lld_rule['key_']] : []) + ['type' => array_key_exists('master_itemid', $lld_rule) ? ITEM_TYPE_DEPENDENT : ITEM_TYPE_TRAPPER]; } public static function convertLldRuleReferences(array &$lld_rules): void { self::convertPropertyReference($lld_rules, 'itemid'); self::convertPropertyReference($lld_rules, 'hostid'); self::convertPropertyReference($lld_rules, 'interfaceid'); self::convertPropertyReference($lld_rules, 'master_itemid'); } /** * @param array $lld_rule * @param int $from * @param int $to * * @return array */ public static function prepareLldRuleSet(array $lld_rule, int $from, int $to): array { if ($from > $to) { throw new Exception('Incorrect range parameters.'); } $bracket_pos = strpos($lld_rule['key_'], '['); $lld_rules = []; for ($i = $from; $i <= $to; $i++) { $key_ = $bracket_pos === false ? $lld_rule['key_'].'.'.$i : substr_replace($lld_rule['key_'], '.'.$i, $bracket_pos, 0); $lld_rules[] = self::prepareLldRule(['key_' => $key_] + $lld_rule); } return $lld_rules; } private static function createTemplateDashboards(array &$dashboards): void { if (!$dashboards) { return; } $host_refs = []; foreach ($dashboards as $i => &$dashboard) { $host_refs[$i] = $dashboard['templateid']; } self::convertTemplateDashboardReferences($dashboards); $result = self::call('templatedashboard.create', $dashboards); foreach ($dashboards as $i => &$dashboard) { $dashboard['dashboardid'] = array_shift($result['dashboardids']); self::$objectids['template_dashboard'][$dashboard['name']][$host_refs[$i]] = $dashboard['dashboardid']; } unset($dashboard); } public static function convertTemplateDashboardReferences(array &$dashboards): void { self::convertPropertyReference($dashboards, 'dashboardid'); self::convertPropertyReference($dashboards, 'templateid'); } private static function createHttptests(array &$httptests): void { if (!$httptests) { return; } $host_refs = []; foreach ($httptests as $i => $httptest) { $host_refs[$i] = $httptest['hostid']; } self::convertHttptestReferences($httptests); $result = self::call('httptest.create', $httptests); foreach ($httptests as $i => &$httptest) { $httptest['httptestid'] = array_shift($result['httptestids']); self::$objectids['httptest'][$httptest['name']][$host_refs[$i]] = $httptest['httptestid']; } unset($httptest); } /** * @param array $httptests */ public static function convertHttptestReferences(array &$httptests): void { self::convertPropertyReference($httptests, 'httptestid'); self::convertPropertyReference($httptests, 'hostid'); } /** * @param array $items */ private static function createItemPrototypes(array &$items): void { if (!$items) { return; } $host_refs = []; $discovered_items = []; $item_indexes = []; foreach ($items as $i => &$item) { $host_refs[$i] = $item['hostid']; $item = self::prepareItemPrototype($item); if (array_key_exists('discovered_items', $item)) { foreach ($item['discovered_items'] as $discovered_item) { $discovered_items[] = $discovered_item + [ 'hostid' => $host_refs[$i], 'item_prototypeid' => ':item_prototype:'.$item['key_'] ]; } unset($item['discovered_items']); } $item_indexes[$item['ruleid']][':item_prototype:'.$item['key_']] = $i; } unset($item); $dep_items = []; foreach ($items as $i => $item) { if ($item['type'] == ITEM_TYPE_DEPENDENT && strpos($item['master_itemid'], ':item_prototype:') === 0) { if (!array_key_exists($item['ruleid'], $item_indexes) || !array_key_exists($item['master_itemid'], $item_indexes[$item['ruleid']])) { throw new Exception(sprintf('Wrong master item ID for item prototype with key "%1$s" on "%2$s".', $item['key_'], $host_refs[$i] )); } $dep_items[$item_indexes[$item['ruleid']][$item['master_itemid']]][$i] = $item; unset($items[$i]); } } $result_items = []; do { self::convertItemPrototypeReferences($items); $result = self::call('itemprototype.create', $items); $_items = []; foreach ($items as $i => &$item) { $item['itemid'] = array_shift($result['itemids']); self::$objectids['item_prototype'][$item['key_']][$host_refs[$i]] = $item['itemid']; if (array_key_exists($i, $dep_items)) { $_items += $dep_items[$i]; } } unset($item); $result_items += $items; } while ($items = $_items); self::createDiscoveredItems($discovered_items); $items = $result_items; } /** * @param array $item * * @return array */ public static function prepareItemPrototype(array $item): array { return $item + [ 'name' => $item['key_'], 'type' => array_key_exists('master_itemid', $item) ? ITEM_TYPE_DEPENDENT : ITEM_TYPE_TRAPPER, 'value_type' => ITEM_VALUE_TYPE_STR ]; } public static function convertItemPrototypeReferences(array &$items): void { self::convertPropertyReference($items, 'itemid'); self::convertPropertyReference($items, 'hostid'); self::convertPropertyReference($items, 'ruleid'); self::convertPropertyReference($items, 'valuemapid'); self::convertPropertyReference($items, 'interfaceid'); self::convertPropertyReference($items, 'master_itemid'); } /** * @param array $item * @param int $from * @param int $to * * @return array * * @throws Exception */ public static function prepareItemPrototypeSet(array $item, int $from, int $to): array { if ($from > $to) { throw new Exception('Incorrect range parameters.'); } $bracket_pos = strpos($item['key_'], '['); $items = []; for ($i = $from; $i <= $to; $i++) { $key_ = $bracket_pos === false ? $item['key_'].'.'.$i : substr_replace($item['key_'], '.'.$i, $bracket_pos, 0); $items[] = self::prepareItemPrototype(['key_' => $key_] + $item); } return $items; } /** * @param array $host_prototypes */ private static function createHostPrototypes(array &$host_prototypes): void { if (!$host_prototypes) { return; } self::convertHostPrototypeReferences($host_prototypes); $result = self::call('hostprototype.create', array_values($host_prototypes)); foreach ($host_prototypes as &$host_prototype) { $host_prototype['hostid'] = array_shift($result['hostids']); self::$objectids['host_prototype'][$host_prototype['host']] = $host_prototype['hostid']; } unset($host_prototype); } public static function convertHostPrototypeReferences(array &$host_prototypes): void { self::convertPropertyReference($host_prototypes, 'hostid'); self::convertPropertyReference($host_prototypes, 'ruleid'); self::convertPropertyReference($host_prototypes, 'groupLinks.groupid'); self::convertPropertyReference($host_prototypes, 'templates.templateid'); } /** * @param array $trigger_prototypes */ private static function createTriggerPrototypes(array &$trigger_prototypes): void { if (!$trigger_prototypes) { return; } self::convertTriggerPrototypeReferences($trigger_prototypes); $result = self::call('triggerprototype.create', array_values($trigger_prototypes)); foreach ($trigger_prototypes as $alias => &$trigger_prototype) { $trigger_prototype['triggerid'] = array_shift($result['triggerids']); self::$objectids['trigger_prototype'][$alias] = $trigger_prototype['triggerid']; } unset($trigger_prototype); } public static function convertTriggerPrototypeReferences(array &$trigger_prototypes): void { self::convertPropertyReference($trigger_prototypes, 'triggerid'); self::convertPropertyReference($trigger_prototypes, 'dependencies.triggerid'); } /** * @param array $graph_prototypes */ private static function createGraphPrototypes(array &$graph_prototypes): void { if (!$graph_prototypes) { return; } self::convertGraphPrototypeReferences($graph_prototypes); $result = self::call('graphprototype.create', array_values($graph_prototypes)); foreach ($graph_prototypes as $alias => &$graph_prototype) { $graph_prototype['graphid'] = array_shift($result['graphids']); self::$objectids['graph_prototype'][$alias] = $graph_prototype['graphid']; } unset($graph_prototype); } public static function convertGraphPrototypeReferences(array &$graph_prototypes): void { self::convertPropertyReference($graph_prototypes, 'graphid'); self::convertPropertyReference($graph_prototypes, 'gitems.itemid'); } /** * @param array $discovered_items */ private static function createDiscoveredItems(array &$discovered_items): void { if (!$discovered_items) { return; } $host_refs = []; $item_indexes = []; $item_prototypeids = []; foreach ($discovered_items as $i => &$item) { $host_refs[$i] = $item['hostid']; $item = self::prepareItem($item); $item_indexes[$item['item_prototypeid']][':discovered_item:'.$item['key_']] = $i; $item_prototypeids[$i] = $item['item_prototypeid']; unset($item['item_prototypeid']); } unset($item); $dep_items = []; foreach ($discovered_items as $i => &$item) { if ($item['type'] == ITEM_TYPE_DEPENDENT && strpos($item['master_itemid'], ':discovered_item:') === 0) { if (!array_key_exists($item_prototypeids[$i], $item_indexes) || !array_key_exists($item['master_itemid'], $item_indexes[$item_prototypeids[$i]])) { throw new Exception(sprintf('Wrong master item ID for discovered item with key "%1$s" on "%2$s".', $item['key_'], $host_refs[$i] )); } $dep_items[$item_indexes[$item_prototypeids[$i]][$item['master_itemid']]][$i] = $item; unset($discovered_items[$i]); } } unset($item); do { self::convertDiscoveredItemReferences($discovered_items); $result = self::call('item.create', $discovered_items); $item_discoveries = []; $_discovered_items = []; foreach ($discovered_items as $i => &$item) { $item['itemid'] = $result['itemids'][$i]; self::$objectids['discovered_item'][$item['key_']][$host_refs[$i]] = $item['itemid']; $item_discoveries[] = [ 'itemid' => $item['itemid'], 'parent_itemid' => $item_prototypeids[$i], 'key_' => $item['key_'] ]; if (array_key_exists($i, $dep_items)) { $_discovered_items += $dep_items[$i]; } } unset($item); self::convertPropertyReference($item_discoveries, 'parent_itemid'); DB::insert('item_discovery', $item_discoveries); DB::update('items', [ 'values' => ['flags' => ZBX_FLAG_DISCOVERY_CREATED], 'where' => ['itemid' => $result['itemids']] ]); } while ($discovered_items = $_discovered_items); } public static function convertDiscoveredItemReferences(array &$discovered_items): void { self::convertPropertyReference($discovered_items, 'itemid'); self::convertPropertyReference($discovered_items, 'hostid'); self::convertPropertyReference($discovered_items, 'item_prototypeid'); self::convertPropertyReference($discovered_items, 'valuemapid'); self::convertPropertyReference($discovered_items, 'interfaceid'); self::convertPropertyReference($discovered_items, 'master_itemid'); } private static function createTriggers(array $triggers): void { if (!$triggers) { return; } foreach ($triggers as $alias => $trigger) { if (is_numeric($alias)) { throw new Exception('Triggers must use aliases as indexes: '.json_encode($trigger)); } elseif (array_key_exists('trigger', self::$objectids) && array_key_exists($alias, self::$objectids['trigger'])) { throw new Exception('Non-unique trigger alias: '.$alias); } } self::convertTriggerReferences($triggers); $result = self::call('trigger.create', array_values($triggers)); foreach ($triggers as $alias => $trigger) { self::$objectids['trigger'][$alias] = array_shift($result['triggerids']); } } public static function convertTriggerReferences(array &$triggers): void { self::convertPropertyReference($triggers, 'triggerid'); self::convertPropertyReference($triggers, 'dependencies.triggerid'); } private static function createRoles(array $roles): void { if (!$roles) { return; } $result = self::call('role.create', $roles); foreach ($roles as $role) { self::$objectids['role'][$role['name']] = array_shift($result['roleids']); } } private static function createUserGroups(array $user_groups): void { if (!$user_groups) { return; } self::convertUserGroupReferences($user_groups); $result = self::call('usergroup.create', $user_groups); foreach ($user_groups as $user_group) { self::$objectids['user_group'][$user_group['name']] = array_shift($result['usrgrpids']); } } public static function convertUserGroupReferences(array &$user_groups): void { self::convertPropertyReference($user_groups, 'usrgrpid'); self::convertPropertyReference($user_groups, 'templategroup_rights.id'); self::convertPropertyReference($user_groups, 'hostgroup_rights.id'); self::convertPropertyReference($user_groups, 'users'); } private static function createUsers(array $users): void { if (!$users) { return; } foreach ($users as &$user) { $user += array_key_exists('role', self::$objectids) ? ['roleid' => end(self::$objectids['role'])] : []; $user += array_key_exists('user_group', self::$objectids) ? ['usrgrps' => [ ['usrgrpid' => end(self::$objectids['user_group'])] ]] : []; } unset($user); self::convertUserReferences($users); $result = self::call('user.create', $users); foreach ($users as $user) { self::$objectids['user'][$user['username']] = array_shift($result['userids']); } } public static function convertUserReferences(array &$users): void { self::convertPropertyReference($users, 'userid'); self::convertPropertyReference($users, 'roleid'); self::convertPropertyReference($users, 'usrgrps.usrgrpid'); } private static function createScripts(array $scripts): void { if (!$scripts) { return; } self::convertScriptReferences($scripts); $result = self::call('script.create', $scripts); foreach ($scripts as $script) { self::$objectids['script'][$script['name']] = array_shift($result['scriptids']); } } public static function convertScriptReferences(array &$scripts): void { self::convertPropertyReference($scripts, 'scriptid'); self::convertPropertyReference($scripts, 'groupid'); self::convertPropertyReference($scripts, 'usrgrpid'); } private static function createDrules(array $drules): void { if (!$drules) { return; } foreach ($drules as &$drule) { $drule = self::prepareDrule($drule); } unset($drule); self::convertDruleReferences($drules); $result = self::call('drule.create', $drules); foreach ($drules as $drule) { self::$objectids['drule'][$drule['name']] = array_shift($result['druleids']); } } /** * @param array $drule * * @return array */ public static function prepareDrule(array $drule): array { return $drule + [ 'iprange' => '192.168.1.1-255', 'dchecks' => [ [ 'type' => SVC_HTTP, 'ports' => '80', 'name' => 'HTTP' ] ] ]; } public static function convertDruleReferences(array &$drules): void { self::convertPropertyReference($drules, 'druleid'); self::convertPropertyReference($drules, 'proxyid'); self::convertPropertyReference($drules, 'proxy_hostid'); } private static function createActions(array $actions): void { if (!$actions) { return; } foreach ($actions as &$action) { if (array_key_exists('filter', $action) && array_key_exists('conditions', $action['filter'])) { $referenced_condition_types = [CONDITION_TYPE_HOST_GROUP, CONDITION_TYPE_HOST, CONDITION_TYPE_TRIGGER, CONDITION_TYPE_TEMPLATE, CONDITION_TYPE_DRULE, CONDITION_TYPE_PROXY ]; foreach ($action['filter']['conditions'] as &$condition) { if (in_array($condition['conditiontype'], $referenced_condition_types)) { if (array_key_exists('value', $condition)) { self::convertValueReference($condition['value']); } } } unset($condition); } } unset($action); self::convertActionReferences($actions); $result = self::call('action.create', $actions); foreach ($actions as $action) { self::$objectids['action'][$action['name']] = array_shift($result['actionids']); } } public static function convertActionReferences(array &$actions): void { self::convertPropertyReference($actions, 'actionid'); self::convertPropertyReference($actions, 'operations.opmessage_grp.usrgrpid'); self::convertPropertyReference($actions, 'operations.opmessage_usr.userid'); self::convertPropertyReference($actions, 'operations.opcommand.scriptid'); self::convertPropertyReference($actions, 'operations.opcommand_grp.groupid'); self::convertPropertyReference($actions, 'operations.opcommand_hst.hostid'); self::convertPropertyReference($actions, 'operations.opgroup.groupid'); self::convertPropertyReference($actions, 'operations.optemplate.templateid'); } private static function createGraphs(array $graphs): void { if (!$graphs) { return; } foreach ($graphs as $alias => $graph) { if (is_numeric($alias)) { throw new Exception('Graphs must use aliases as indexes: '.json_encode($graph)); } elseif (array_key_exists('graph', self::$objectids) && array_key_exists($alias, self::$objectids['graph'])) { throw new Exception('Non-unique graph alias: '.$alias); } } self::convertGraphReferences($graphs); $result = self::call('graph.create', array_values($graphs)); foreach ($graphs as $alias => $graph) { self::$objectids['graph'][$alias] = array_shift($result['graphids']); } } public static function convertGraphReferences(array &$graphs): void { self::convertPropertyReference($graphs, 'graphid'); self::convertPropertyReference($graphs, 'gitems.itemid'); } private static function createDashboards(array &$dashboards): void { if (!$dashboards) { return; } self::convertDashboardReferences($dashboards); $result = self::call('dashboard.create', $dashboards); foreach ($dashboards as &$dashboard) { $dashboard['dashboardid'] = array_shift($result['dashboardids']); self::$objectids['dashboard'][$dashboard['name']] = $dashboard['dashboardid']; } unset($dashboard); } public static function convertDashboardReferences(array &$dashboards): void { self::convertPropertyReference($dashboards, 'dashboardid'); self::convertPropertyReference($dashboards, 'userid'); self::convertPropertyReference($dashboards, 'pages.widgets.fields.value'); self::convertPropertyReference($dashboards, 'users.userid'); self::convertPropertyReference($dashboards, 'userGroups.usrgrpid'); } private static function createServices(array &$services): void { if (!$services) { return; } foreach ($services as &$service) { $service = self::prepareService($service); } unset($service); self::convertServiceReferences($services); $result = self::call('service.create', $services); foreach ($services as $service) { self::$objectids['service'][$service['name']] = array_shift($result['serviceids']); } } /** * @param array $service * * @return array */ public static function prepareService(array $service): array { return $service + [ 'algorithm' => ZBX_SERVICE_STATUS_CALC_SET_OK, 'sortorder' => '0' ]; } public static function convertServiceReferences(array &$services): void { self::convertPropertyReference($services, 'serviceid'); self::convertPropertyReference($services, 'parents.serviceid'); self::convertPropertyReference($services, 'children.serviceid'); } private static function createMaintenances(array &$maintenances): void { if (!$maintenances) { return; } foreach ($maintenances as &$maintenance) { $maintenance = self::prepareMaintenance($maintenance); } unset($maintenance); self::convertMaintenanceReferences($maintenances); $result = self::call('maintenance.create', $maintenances); foreach ($maintenances as $maintenance) { self::$objectids['maintenance'][$maintenance['name']] = array_shift($result['maintenanceids']); } } /** * @param array $maintenance * * @return array */ public static function prepareMaintenance(array $maintenance): array { return $maintenance + [ 'active_since' => time(), 'active_till' => strtotime('now + 1 year') ]; } public static function convertMaintenanceReferences(array &$maintenances): void { self::convertPropertyReference($maintenances, 'maintenanceid'); self::convertPropertyReference($maintenances, 'groups.groupid'); self::convertPropertyReference($maintenances, 'hosts.hostid'); } private static function createCorrelations(array &$correlations): void { if (!$correlations) { return; } self::convertCorrelationReferences($correlations); $result = self::call('correlation.create', $correlations); foreach ($correlations as $correlation) { self::$objectids['correlation'][$correlation['name']] = array_shift($result['correlationids']); } } public static function convertCorrelationReferences(array &$correlations): void { self::convertPropertyReference($correlations, 'correlationid'); self::convertPropertyReference($correlations, 'filter.conditions.groupid'); } private static function createSlas(array &$slas): void { if (!$slas) { return; } foreach ($slas as &$sla) { $sla = self::prepareSla($sla); } unset($sla); self::converSlaReferences($slas); $result = self::call('sla.create', $slas); foreach ($slas as $sla) { self::$objectids['sla'][$sla['name']] = array_shift($result['slaids']); } } /** * @param array $sla * * @return array */ public static function prepareSla(array $sla): array { return $sla + [ 'period' => ZBX_SLA_PERIOD_DAILY, 'slo' => 99.9999, 'timezone' => 'Europe/Riga' ]; } public static function converSlaReferences(array &$slas): void { self::convertPropertyReference($slas, 'slaid'); self::convertPropertyReference($slas, 'filter.conditions.groupid'); } private static function createReports(array &$reports): void { if (!$reports) { return; } self::converReportReferences($reports); $result = self::call('report.create', $reports); foreach ($reports as $report) { self::$objectids['report'][$report['name']] = array_shift($result['reportids']); } } public static function converReportReferences(array &$reports): void { self::convertPropertyReference($reports, 'reportid'); self::convertPropertyReference($reports, 'userid'); self::convertPropertyReference($reports, 'dashboardid'); self::convertPropertyReference($reports, 'users.userid'); self::convertPropertyReference($reports, 'users.access_userid'); self::convertPropertyReference($reports, 'user_groups.usrgrpid'); self::convertPropertyReference($reports, 'user_groups.access_userid'); } /** * Check for, and replace a reference ID in the given objects' property with the corresponding object's record ID. * * @param array $objects Array of objects containing the referenced property. * @param string $property The reference key. A "." symbol is used as a separator for nested property references, * f.e., `templates.templateid`. In case of matching object names (e.g. item inherited from * template to host), the contained reference should include further specific parent object * references, e.g.: `:item:item.key:host:my.name` vs `:items:item.key:template:my.name`. */ private static function convertPropertyReference(array &$objects, string $property): void { is_numeric(key($objects)) ? self::convertPropertyReferenceForObjects($objects, $property) : self::convertPropertyReferenceForObject($objects, $property); } private static function convertPropertyReferenceForObjects(array &$objects, string $property): void { $nested = strpos($property, '.') !== false; if ($nested) { [$property, $sub_property] = explode('.', $property, 2); } foreach ($objects as &$object) { if (!array_key_exists($property, $object)) { continue; } elseif (!$nested) { self::convertValueReference($object[$property]); continue; } if (strpos($sub_property, '.') !== false) { self::convertPropertyReference($object[$property], $sub_property); continue; } if (is_numeric(key($object[$property]))) { foreach ($object[$property] as &$_object) { if (array_key_exists($sub_property, $_object)) { self::convertValueReference($_object[$sub_property]); } } unset($_object); } else { self::convertValueReference($object[$property][$sub_property]); } } unset($object); } private static function convertPropertyReferenceForObject(array &$object, string $property): void { $nested = strpos($property, '.') !== false; if ($nested) { [$property, $sub_property] = explode('.', $property, 2); } if (array_key_exists($property, $object)) { if ($nested) { is_numeric(key($object[$property])) ? self::convertPropertyReferenceForObjects($object[$property], $sub_property) : self::convertPropertyReferenceForObject($object[$property], $sub_property); } else { self::convertValueReference($object[$property]); } } } public static function unsetDeletedObjectIds(array $objectids): void { foreach ($objectids as $objectid) { self::convertValueReference($objectid, true); } } public static function getConvertedValueReferences(array $values): array { self::convertValueReferences($values); return $values; } public static function convertValueReferences(array &$values): void { foreach ($values as &$value) { self::convertValueReference($value); } unset($value); } public static function getConvertedValueReference(string $value): string { self::convertValueReference($value); return $value; } /** * Check for, and replace a reference ID in the given value with the corresponding object's record ID. * * @param string $value The value possibly containing the reference. In case of matching object names (e.g. item * inherited from template to host), the contained reference should include further specific * parent object references, e.g.: `:item:item.key:host:my.name` vs * `:items:item.key:template:my.name`. * @param bool $unset Whether to unset the value from the $objectids array, if it is convertible. */ private static function convertValueReference(string &$value, bool $unset = false): void { if (!is_string($value) || $value === '' || $value[0] !== ':') { return; } $colon_positions = [0]; $p = 0; while ($p = strpos($value, ':', $p + 1)) { if ($value[$p - 1] !== '\\') { $colon_positions[] = $p; } } if (count($colon_positions) % 2 != 0 || !isset($value[end($colon_positions) + 1])) { return; } $object_type = substr($value, $colon_positions[0] + 1, $colon_positions[1] - 1); $name = substr($value, $colon_positions[1] + 1, array_key_exists(2, $colon_positions) ? $colon_positions[2] - $colon_positions[1] - 1 : strlen($value) - $colon_positions[1] - 1 ); unset($colon_positions[0], $colon_positions[1]); if (!array_key_exists($object_type, self::$objectids) || !array_key_exists($name, self::$objectids[$object_type]) || ($colon_positions && !is_array(self::$objectids[$object_type][$name]))) { return; } if (!$colon_positions) { $objectid = self::$objectids[$object_type][$name]; if ($unset) { unset(self::$objectids[$object_type][$name]); if (!self::$objectids[$object_type]) { unset(self::$objectids[$object_type]); } } while (is_array($objectid)) { $objectid = end($objectid); } $value = $objectid; return; } $objectid = self::$objectids[$object_type][$name]; while ($colon_positions) { if (!is_array($objectid)) { return; } $colon_start = array_shift($colon_positions); array_shift($colon_positions); $ref = $colon_positions ? substr($value, $colon_start, reset($colon_positions) - $colon_start - 1) : substr($value, $colon_start); if (!array_key_exists($ref, $objectid)) { return; } $objectid = $objectid[$ref]; } $value = $objectid; } /** * Delete inserted objects from the database and reset internal data. */ public static function cleanUp(): void { if (array_key_exists('report', self::$objectids)) { self::call('report.delete', array_values(self::$objectids['report'])); } if (array_key_exists('sla', self::$objectids)) { self::call('sla.delete', array_values(self::$objectids['sla'])); } if (array_key_exists('correlation', self::$objectids)) { self::call('correlation.delete', array_values(self::$objectids['correlation'])); } if (array_key_exists('maintenance', self::$objectids)) { self::call('maintenance.delete', array_values(self::$objectids['maintenance'])); } if (array_key_exists('service', self::$objectids)) { self::call('service.delete', array_values(self::$objectids['service'])); } if (array_key_exists('dashboard', self::$objectids)) { self::call('dashboard.delete', array_values(self::$objectids['dashboard'])); } if (array_key_exists('graph', self::$objectids)) { self::call('graph.delete', array_values(self::$objectids['graph'])); } if (array_key_exists('action', self::$objectids)) { self::call('action.delete', array_values(self::$objectids['action'])); } if (array_key_exists('drule', self::$objectids)) { self::call('drule.delete', array_values(self::$objectids['drule'])); } if (array_key_exists('script', self::$objectids)) { self::call('script.delete', array_values(self::$objectids['script'])); } if (array_key_exists('user', self::$objectids)) { self::call('user.delete', array_values(self::$objectids['user'])); } if (array_key_exists('user_group', self::$objectids)) { self::call('usergroup.delete', array_values(self::$objectids['user_group'])); } if (array_key_exists('role', self::$objectids)) { self::call('role.delete', array_values(self::$objectids['role'])); } if (array_key_exists('template', self::$objectids)) { self::call('template.delete', array_values(self::$objectids['template'])); } if (array_key_exists('host', self::$objectids)) { self::call('host.delete', array_values(self::$objectids['host'])); } if (array_key_exists('proxy', self::$objectids)) { self::call('proxy.delete', array_values(self::$objectids['proxy'])); } if (array_key_exists('template_group', self::$objectids)) { ZABBIX_VERSION < 6.4 ? self::call('hostgroup.delete', array_values(self::$objectids['template_group'])) : self::call('templategroup.delete', array_values(self::$objectids['template_group'])); } if (array_key_exists('host_group', self::$objectids)) { self::call('hostgroup.delete', array_values(self::$objectids['host_group'])); } if (array_key_exists('value_map', self::$detachedids)) { self::call('valuemap.delete', array_values(self::$detachedids['value_map'])); } if (array_key_exists('httptest', self::$detachedids)) { self::call('httptest.delete', array_values(self::$detachedids['httptest'])); } if (array_key_exists('item', self::$detachedids)) { self::call('item.delete', array_values(self::$detachedids['item'])); } if (array_key_exists('graph_prototype', self::$detachedids)) { self::call('graphprototype.delete', array_values(self::$detachedids['graph_prototype'])); } if (array_key_exists('trigger_prototype', self::$detachedids)) { self::call('triggerprototype.delete', array_values(self::$detachedids['trigger_prototype'])); } if (array_key_exists('host_prototype', self::$detachedids)) { self::call('hostprototype.delete', array_values(self::$detachedids['host_prototype'])); } if (array_key_exists('item_prototype', self::$detachedids)) { self::call('itemprototype.delete', array_values(self::$detachedids['item_prototype'])); } if (array_key_exists('lld_rule', self::$detachedids)) { self::call('discoveryrule.delete', array_values(self::$detachedids['lld_rule'])); } if (array_key_exists('template_dashboard', self::$detachedids)) { self::call('templatedashboard.delete', array_values(self::$detachedids['template_dashboard'])); } self::$objectids = []; self::$detachedids = []; } private static function prepareEnabledGuestUser(): array { $guest = self::call('user.get', [ 'output' => ['userid'], 'filter' => ['username' => 'guest'], 'selectUsrgrps' => ['usrgrpid', 'name'] ])[0]; if (!in_array('Disabled', array_column($guest['usrgrps'], 'name'))) { return []; } foreach ($guest['usrgrps'] as $i => &$group) { if ($group['name'] === 'Disabled') { unset($guest['usrgrps'][$i]); continue; } $group = ['usrgrpid' => $group['usrgrpid']]; } unset($group); return $guest; } private static function prepareDisabledGuestUser(): array { $guest = self::call('user.get', [ 'output' => ['userid'], 'filter' => ['username' => 'guest'], 'selectUsrgrps' => ['usrgrpid', 'name'] ])[0]; if (in_array('Disabled', array_column($guest['usrgrps'], 'name'))) { return []; } $groups = self::call('usergroup.get', [ 'output' => ['usrgrpid', 'name'], 'filter' => ['name' => 'Disabled'] ]); $guest['usrgrps'] = array_merge($guest['usrgrps'] , $groups); foreach ($guest['usrgrps'] as &$group) { $group = ['usrgrpid' => $group['usrgrpid']]; } unset($group); return $guest; } /** * Removes the 'Disabled' user group from guest user, keeping the others. */ public static function enableGuestUser(): void { $guest= self::prepareEnabledGuestUser(); if ($guest) { self::call('user.update', $guest); } } /** * Assigns the 'Disabled' user group to guest user, keeping the others. */ public static function disableGuestUser(): void { $guest = self::prepareDisabledGuestUser(); if ($guest) { self::call('user.update', $guest); } } }