✏️ 正在编辑: CConfigurationImport.php
路径:
/usr/share/zabbix/include/classes/import/CConfigurationImport.php
提示:
您可以编辑任何文件(包括二进制文件),但请注意不当修改可能导致文件损坏。
<?php /* ** Zabbix ** Copyright (C) 2001-2021 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 for importing configuration data. */ class CConfigurationImport { /** * @var CImportDataAdapter */ protected $adapter; /** * @var CImportReferencer */ protected $referencer; /** * @var CImportedObjectContainer */ protected $importedObjectContainer; /** * @var array */ protected $options; /** * @var array with data read from source string */ protected $data; /** * @var array cached data from the adapter */ protected $formattedData = []; /** * Constructor. * Source string must be suitable for reader class, * i.e. if string contains json then reader should be able to read json. * * @param array $options import options "createMissing", "updateExisting" and "deleteMissing" * @param CImportReferencer $referencer class containing all importable objects * @param CImportedObjectContainer $importedObjectContainer class containing processed host and template IDs */ public function __construct(array $options = [], CImportReferencer $referencer, CImportedObjectContainer $importedObjectContainer) { $default_options = [ 'groups' => ['createMissing' => false], 'hosts' => ['updateExisting' => false, 'createMissing' => false], 'templates' => ['updateExisting' => false, 'createMissing' => false], 'templateDashboards' => ['updateExisting' => false, 'createMissing' => false, 'deleteMissing' => false], 'applications' => ['createMissing' => false, 'deleteMissing' => false], 'templateLinkage' => ['createMissing' => false, 'deleteMissing' => false], 'items' => ['updateExisting' => false, 'createMissing' => false, 'deleteMissing' => false], 'discoveryRules' => ['updateExisting' => false, 'createMissing' => false, 'deleteMissing' => false], 'triggers' => ['updateExisting' => false, 'createMissing' => false, 'deleteMissing' => false], 'graphs' => ['updateExisting' => false, 'createMissing' => false, 'deleteMissing' => false], 'httptests' => ['updateExisting' => false, 'createMissing' => false, 'deleteMissing' => false], 'screens' => ['updateExisting' => false, 'createMissing' => false], 'maps' => ['updateExisting' => false, 'createMissing' => false], 'images' => ['updateExisting' => false, 'createMissing' => false], 'mediaTypes' => ['updateExisting' => false, 'createMissing' => false], 'valueMaps' => ['updateExisting' => false, 'createMissing' => false] ]; $options = array_merge($default_options, $options); $object_options = ( $options['templateLinkage']['createMissing'] || $options['templateLinkage']['deleteMissing'] || $options['applications']['createMissing'] || $options['applications']['deleteMissing'] || $options['items']['updateExisting'] || $options['items']['createMissing'] || $options['items']['deleteMissing'] || $options['discoveryRules']['updateExisting'] || $options['discoveryRules']['createMissing'] || $options['discoveryRules']['deleteMissing'] || $options['triggers']['deleteMissing'] || $options['graphs']['deleteMissing'] || $options['httptests']['updateExisting'] || $options['httptests']['createMissing'] || $options['httptests']['deleteMissing'] ); $options['process_templates'] = ( !$options['templates']['updateExisting'] && ($object_options || $options['templateDashboards']['updateExisting'] || $options['templateDashboards']['createMissing'] || $options['templateDashboards']['deleteMissing'] ) ); $options['process_hosts'] = (!$options['hosts']['updateExisting'] && $object_options); $this->options = $options; $this->referencer = $referencer; $this->importedObjectContainer = $importedObjectContainer; } /** * Import configuration data. * * @param CImportDataAdapter $adapter an object to provide access to the imported data * * @return bool */ public function import(CImportDataAdapter $adapter) { $this->adapter = $adapter; // parse all import for references to resolve them all together with less sql count $this->gatherReferences(); $this->processGroups(); $this->processTemplates(); $this->processHosts(); // delete missing objects from processed hosts and templates $this->deleteMissingHttpTests(); $this->deleteMissingDiscoveryRules(); $this->deleteMissingTriggers(); $this->deleteMissingGraphs(); $this->deleteMissingItems(); // import objects $this->processApplications(); $this->processValueMaps(); $this->processHttpTests(); $this->processItems(); $this->processTriggers(); $this->processDiscoveryRules(); $this->processGraphs(); $this->processImages(); $this->processMaps(); $this->processTemplateDashboards(); $this->processScreens(); $this->processMediaTypes(); // Missing applications should be deleted after new application changes are done to all inherited items. $this->deleteMissingApplications(); return true; } /** * Parse all import data and collect references to objects. * For host objects it collects host names, for items - host name and item key, etc. * Collected references are added and resolved via the $this->referencer object. * * @see CImportReferencer */ protected function gatherReferences() { $groupsRefs = []; $templatesRefs = []; $hostsRefs = []; $applicationsRefs = []; $itemsRefs = []; $valueMapsRefs = []; $triggersRefs = []; $graphsRefs = []; $iconMapsRefs = []; $mapsRefs = []; $screensRefs = []; $templateDashboardsRefs = []; $macrosRefs = []; $proxyRefs = []; $hostPrototypesRefs = []; $httptestsRefs = []; $httpstepsRefs = []; foreach ($this->getFormattedGroups() as $group) { $groupsRefs[$group['name']] = $group['name']; } foreach ($this->getFormattedTemplates() as $template) { $templatesRefs[$template['host']] = $template['host']; foreach ($template['groups'] as $group) { $groupsRefs[$group['name']] = $group['name']; } if (array_key_exists('macros', $template)) { foreach ($template['macros'] as $macro) { $macrosRefs[$template['host']][$macro['macro']] = $macro['macro']; } } if (!empty($template['templates'])) { foreach ($template['templates'] as $linkedTemplate) { $templatesRefs[$linkedTemplate['name']] = $linkedTemplate['name']; } } } foreach ($this->getFormattedHosts() as $host) { $hostsRefs[$host['host']] = $host['host']; foreach ($host['groups'] as $group) { $groupsRefs[$group['name']] = $group['name']; } if (array_key_exists('macros', $host)) { foreach ($host['macros'] as $macro) { $macrosRefs[$host['host']][$macro['macro']] = $macro['macro']; } } if (!empty($host['templates'])) { foreach ($host['templates'] as $linkedTemplate) { $templatesRefs[$linkedTemplate['name']] = $linkedTemplate['name']; } } if (!empty($host['proxy'])) { $proxyRefs[$host['proxy']['name']] = $host['proxy']['name']; } } foreach ($this->getFormattedApplications() as $host => $applications) { foreach ($applications as $app) { $applicationsRefs[$host][$app['name']] = $app['name']; } } foreach ($this->getFormattedValueMaps() as $valuemap) { $valueMapsRefs[$valuemap['name']] = $valuemap['name']; } foreach ($this->getFormattedItems() as $host => $items) { foreach ($items as $item) { $itemsRefs[$host][$item['key_']] = $item['key_']; foreach ($item['applications'] as $app) { $applicationsRefs[$host][$app['name']] = $app['name']; } if (!empty($item['valuemap'])) { $valueMapsRefs[$item['valuemap']['name']] = $item['valuemap']['name']; } } } foreach ($this->getFormattedDiscoveryRules() as $host => $discoveryRules) { foreach ($discoveryRules as $discoveryRule) { $itemsRefs[$host][$discoveryRule['key_']] = $discoveryRule['key_']; foreach ($discoveryRule['item_prototypes'] as $itemp) { $itemsRefs[$host][$itemp['key_']] = $itemp['key_']; foreach ($itemp['applications'] as $app) { $applicationsRefs[$host][$app['name']] = $app['name']; } if (!empty($itemp['valuemap'])) { $valueMapsRefs[$itemp['valuemap']['name']] = $itemp['valuemap']['name']; } } foreach ($discoveryRule['trigger_prototypes'] as $trigger) { $triggersRefs[$trigger['description']][$trigger['expression']][$trigger['recovery_expression']] = true; if (array_key_exists('dependencies', $trigger)) { foreach ($trigger['dependencies'] as $dependency) { $name = $dependency['name']; $expression = $dependency['expression']; $recovery_expression = $dependency['recovery_expression']; $triggersRefs[$name][$expression][$recovery_expression] = true; } } } foreach ($discoveryRule['graph_prototypes'] as $graph) { if ($graph['ymin_item_1']) { $yMinItem = $graph['ymin_item_1']; $itemsRefs[$yMinItem['host']][$yMinItem['key']] = $yMinItem['key']; } if ($graph['ymax_item_1']) { $yMaxItem = $graph['ymax_item_1']; $itemsRefs[$yMaxItem['host']][$yMaxItem['key']] = $yMaxItem['key']; } foreach ($graph['gitems'] as $gitem) { $gitemItem = $gitem['item']; $hostsRefs[$gitemItem['host']] = $gitemItem['host']; $itemsRefs[$gitemItem['host']][$gitemItem['key']] = $gitemItem['key']; $graphsRefs[$gitemItem['host']][$graph['name']] = $graph['name']; } } foreach ($discoveryRule['host_prototypes'] as $hostPrototype) { $hostPrototypesRefs[$host][$discoveryRule['key_']][$hostPrototype['host']] = $hostPrototype['host']; foreach ($hostPrototype['group_prototypes'] as $groupPrototype) { if (isset($groupPrototype['group'])) { $groupsRefs[$groupPrototype['group']['name']] = $groupPrototype['group']['name']; } } foreach ($hostPrototype['templates'] as $template) { $templatesRefs[$template['name']] = $template['name']; } } if ($discoveryRule['overrides']) { foreach ($discoveryRule['overrides'] as $override) { foreach ($override['operations'] as $operation) { if ($operation['operationobject'] == OPERATION_OBJECT_HOST_PROTOTYPE && array_key_exists('optemplate', $operation)) { foreach ($operation['optemplate'] as $template) { $templatesRefs[$template['name']] = $template['name']; } } } } } } } foreach ($this->getFormattedGraphs() as $graph) { if ($graph['ymin_item_1']) { $yMinItem = $graph['ymin_item_1']; $hostsRefs[$yMinItem['host']] = $yMinItem['host']; $itemsRefs[$yMinItem['host']][$yMinItem['key']] = $yMinItem['key']; } if ($graph['ymax_item_1']) { $yMaxItem = $graph['ymax_item_1']; $hostsRefs[$yMaxItem['host']] = $yMaxItem['host']; $itemsRefs[$yMaxItem['host']][$yMaxItem['key']] = $yMaxItem['key']; } if (isset($graph['gitems']) && $graph['gitems']) { foreach ($graph['gitems'] as $gitem) { $gitemItem = $gitem['item']; $hostsRefs[$gitemItem['host']] = $gitemItem['host']; $itemsRefs[$gitemItem['host']][$gitemItem['key']] = $gitemItem['key']; $graphsRefs[$gitemItem['host']][$graph['name']] = $graph['name']; } } } foreach ($this->getFormattedTriggers() as $trigger) { $triggersRefs[$trigger['description']][$trigger['expression']][$trigger['recovery_expression']] = true; if (array_key_exists('dependencies', $trigger)) { foreach ($trigger['dependencies'] as $dependency) { $triggersRefs[$dependency['name']][$dependency['expression']][$dependency['recovery_expression']] = true; } } } foreach ($this->getFormattedMaps() as $map) { $mapsRefs[$map['name']] = $map['name']; if (!empty($map['iconmap'])) { $iconMapsRefs[$map['iconmap']['name']] = $map['iconmap']['name']; } if (isset($map['selements'])) { foreach ($map['selements'] as $selement) { switch ($selement['elementtype']) { case SYSMAP_ELEMENT_TYPE_MAP: $mapsRefs[$selement['elements'][0]['name']] = $selement['elements'][0]['name']; break; case SYSMAP_ELEMENT_TYPE_HOST_GROUP: $groupsRefs[$selement['elements'][0]['name']] = $selement['elements'][0]['name']; break; case SYSMAP_ELEMENT_TYPE_HOST: $hostsRefs[$selement['elements'][0]['host']] = $selement['elements'][0]['host']; break; case SYSMAP_ELEMENT_TYPE_TRIGGER: foreach ($selement['elements'] as $element) { $triggersRefs[$element['description']][$element['expression']][$element['recovery_expression']] = true; } break; } } } if (isset($map['links'])) { foreach ($map['links'] as $link) { if (isset($link['linktriggers'])) { foreach ($link['linktriggers'] as $linkTrigger) { $t = $linkTrigger['trigger']; $triggersRefs[$t['description']][$t['expression']][$t['recovery_expression']] = true; } } } } } foreach ($this->getFormattedScreens() as $screen) { $screensRefs[$screen['name']] = $screen['name']; if (!empty($screen['screenitems'])) { foreach ($screen['screenitems'] as $screenItem) { $resource = $screenItem['resource']; if (empty($resource)) { continue; } switch ($screenItem['resourcetype']) { case SCREEN_RESOURCE_HOST_INFO: case SCREEN_RESOURCE_TRIGGER_INFO: case SCREEN_RESOURCE_TRIGGER_OVERVIEW: case SCREEN_RESOURCE_DATA_OVERVIEW: case SCREEN_RESOURCE_HOSTGROUP_TRIGGERS: $groupsRefs[$resource['name']] = $resource['name']; break; case SCREEN_RESOURCE_HOST_TRIGGERS: $hostsRefs[$resource['host']] = $resource['host']; break; case SCREEN_RESOURCE_GRAPH: case SCREEN_RESOURCE_LLD_GRAPH: $hostsRefs[$resource['host']] = $resource['host']; $graphsRefs[$resource['host']][$resource['name']] = $resource['name']; break; case SCREEN_RESOURCE_CLOCK: if ($screenItem['style'] != TIME_TYPE_HOST) { break; } // break; is not missing here case SCREEN_RESOURCE_SIMPLE_GRAPH: case SCREEN_RESOURCE_LLD_SIMPLE_GRAPH: case SCREEN_RESOURCE_PLAIN_TEXT: $hostsRefs[$resource['host']] = $resource['host']; $itemsRefs[$resource['host']][$resource['key']] = $resource['key']; break; case SCREEN_RESOURCE_MAP: $mapsRefs[$resource['name']] = $resource['name']; break; } } } } foreach ($this->getFormattedTemplateDashboards() as $dashboards) { foreach ($dashboards as $dashboard) { $templateDashboardsRefs[$dashboard['name']] = $dashboard['name']; if ($dashboard['widgets']) { foreach ($dashboard['widgets'] as $widget) { foreach ($widget['fields'] as $field) { $value = $field['value']; switch ($field['type']) { case ZBX_WIDGET_FIELD_TYPE_ITEM: case ZBX_WIDGET_FIELD_TYPE_ITEM_PROTOTYPE: $hostsRefs[$value['host']] = $value['host']; $itemsRefs[$value['host']][$value['key']] = $value['key']; break; case ZBX_WIDGET_FIELD_TYPE_GRAPH: case ZBX_WIDGET_FIELD_TYPE_GRAPH_PROTOTYPE: $hostsRefs[$value['host']] = $value['host']; $graphsRefs[$value['host']][$value['name']] = $value['name']; break; } } } } } } foreach ($this->getFormattedHttpTests() as $host => $httptests) { foreach ($httptests as $httptest) { $httptestsRefs[$host][$httptest['name']] = $httptest['name']; if (array_key_exists('name', $httptest['application'])) { $applicationsRefs[$host][$httptest['application']['name']] = $httptest['application']['name']; } } } foreach ($this->getFormattedHttpSteps() as $host => $httptests) { foreach ($httptests as $httptest_name => $httpsteps) { foreach ($httpsteps as $httpstep) { $httpstepsRefs[$host][$httptest_name][$httpstep['name']] = $httpstep['name']; } } } $this->referencer->addGroups($groupsRefs); $this->referencer->addTemplates($templatesRefs); $this->referencer->addHosts($hostsRefs); $this->referencer->addApplications($applicationsRefs); $this->referencer->addItems($itemsRefs); $this->referencer->addValueMaps($valueMapsRefs); $this->referencer->addTriggers($triggersRefs); $this->referencer->addGraphs($graphsRefs); $this->referencer->addIconMaps($iconMapsRefs); $this->referencer->addMaps($mapsRefs); $this->referencer->addScreens($screensRefs); $this->referencer->addTemplateDashboards($templateDashboardsRefs); $this->referencer->addMacros($macrosRefs); $this->referencer->addProxies($proxyRefs); $this->referencer->addHostPrototypes($hostPrototypesRefs); $this->referencer->addHttpTests($httptestsRefs); $this->referencer->addHttpSteps($httpstepsRefs); } /** * Import groups. * * @return null */ protected function processGroups() { if (!$this->options['groups']['createMissing']) { return; } $groups = $this->getFormattedGroups(); if (empty($groups)) { return; } // skip the groups that already exist foreach ($groups as $gnum => $group) { if ($this->referencer->resolveGroup($group['name'])) { unset($groups[$gnum]); } } if ($groups) { // reset indexing because ids from api does not preserve input array keys $groups = array_values($groups); $newGroups = API::HostGroup()->create($groups); foreach ($newGroups['groupids'] as $gnum => $groupid) { $this->referencer->addGroupRef($groups[$gnum]['name'], $groupid); } } } /** * Import templates. * * @throws Exception */ protected function processTemplates() { if ($this->options['templates']['updateExisting'] || $this->options['templates']['createMissing'] || $this->options['process_templates']) { $templates = $this->getFormattedTemplates(); if ($templates) { $templateImporter = new CTemplateImporter($this->options, $this->referencer, $this->importedObjectContainer ); $templateImporter->import($templates); // get list of imported template IDs and add them processed template ID list $templateIds = $templateImporter->getProcessedTemplateIds(); $this->importedObjectContainer->addTemplateIds($templateIds); } } } /** * Import hosts. * * @throws Exception */ protected function processHosts() { if ($this->options['hosts']['updateExisting'] || $this->options['hosts']['createMissing'] || $this->options['process_hosts']) { $hosts = $this->getFormattedHosts(); if ($hosts) { $hostImporter = new CHostImporter($this->options, $this->referencer, $this->importedObjectContainer); $hostImporter->import($hosts); // get list of imported host IDs and add them processed host ID list $hostIds = $hostImporter->getProcessedHostIds(); $this->importedObjectContainer->addHostIds($hostIds); } } } /** * Import applications. */ protected function processApplications() { if (!$this->options['applications']['createMissing']) { return; } $allApplications = $this->getFormattedApplications(); if (!$allApplications) { return; } $applicationsToCreate = []; foreach ($allApplications as $host => $applications) { $hostId = $this->referencer->resolveHostOrTemplate($host); if (!$this->importedObjectContainer->isHostProcessed($hostId) && !$this->importedObjectContainer->isTemplateProcessed($hostId)) { continue; } foreach ($applications as $application) { $application['hostid'] = $hostId; $appId = $this->referencer->resolveApplication($hostId, $application['name']); if (!$appId) { $applicationsToCreate[] = $application; } } } if ($applicationsToCreate) { API::Application()->create($applicationsToCreate); } // refresh applications because templated ones can be inherited to host and used in items $this->referencer->refreshApplications(); } /** * Import value maps. */ protected function processValueMaps() { if (!$this->options['valueMaps']['createMissing'] && !$this->options['valueMaps']['updateExisting']) { return; } $all_valuemaps = $this->getFormattedValueMaps(); if (!$all_valuemaps) { return; } $valuemaps_to_create = []; $valuemaps_to_update = []; foreach ($all_valuemaps as $valuemap) { $valuemapid = $this->referencer->resolveValueMap($valuemap['name']); if ($valuemapid) { $valuemap['valuemapid'] = $valuemapid; $valuemaps_to_update[] = $valuemap; } else { $valuemaps_to_create[] = $valuemap; } } if ($this->options['valueMaps']['createMissing'] && $valuemaps_to_create) { $valuemapids = API::ValueMap()->create($valuemaps_to_create); foreach ($valuemaps_to_create as $key => $valuemap) { $this->referencer->addValueMapRef($valuemap['name'], $valuemapids['valuemapids'][$key]); } } if ($this->options['valueMaps']['updateExisting'] && $valuemaps_to_update) { API::ValueMap()->update($valuemaps_to_update); } } /** * Import items. */ protected function processItems() { if (!$this->options['items']['createMissing'] && !$this->options['items']['updateExisting']) { return; } $allItems = $this->getFormattedItems(); if (!$allItems) { return; } $xml_itemkey = 'master_item'; $order_tree = $this->getItemsOrder($xml_itemkey); $items_to_create = []; $items_to_update = []; foreach ($allItems as $host => $items) { $hostId = $this->referencer->resolveHostOrTemplate($host); if (!$this->importedObjectContainer->isHostProcessed($hostId) && !$this->importedObjectContainer->isTemplateProcessed($hostId)) { continue; } foreach ($order_tree[$host] as $index => $level) { $item = $items[$index]; $item['hostid'] = $hostId; if (isset($item['applications']) && $item['applications']) { $applicationsIds = []; foreach ($item['applications'] as $application) { $applicationid = $this->referencer->resolveApplication($hostId, $application['name']); if ($applicationid) { $applicationsIds[] = $applicationid; } else { throw new Exception(_s('Item "%1$s" on "%2$s": application "%3$s" does not exist.', $item['name'], $host, $application['name'])); } } $item['applications'] = $applicationsIds; } if (array_key_exists('interface_ref', $item) && $item['interface_ref']) { $interfaceid = $this->referencer->resolveInterface($hostId, $item['interface_ref']); if ($interfaceid) { $item['interfaceid'] = $interfaceid; } else { throw new Exception(_s('Cannot find interface "%1$s" used for item "%2$s" on "%3$s".', $item['interface_ref'], $item['name'], $host )); } } if (isset($item['valuemap']) && $item['valuemap']) { $valueMapId = $this->referencer->resolveValueMap($item['valuemap']['name']); if (!$valueMapId) { throw new Exception(_s( 'Cannot find value map "%1$s" used for item "%2$s" on "%3$s".', $item['valuemap']['name'], $item['name'], $host )); } $item['valuemapid'] = $valueMapId; } if ($item['type'] == ITEM_TYPE_DEPENDENT) { if (!array_key_exists('key', $item[$xml_itemkey])) { throw new Exception(_s('Incorrect value for field "%1$s": %2$s.', 'master_itemid', _('cannot be empty') )); } $master_itemid = $this->referencer->resolveItem($hostId, $item[$xml_itemkey]['key']); if ($master_itemid !== false) { $item['master_itemid'] = $master_itemid; unset($item[$xml_itemkey]); } } else { unset($item[$xml_itemkey]); } if ($item['type'] == ITEM_TYPE_HTTPAGENT) { $headers = []; foreach ($item['headers'] as $header) { $headers[$header['name']] = $header['value']; } $item['headers'] = $headers; $query_fields = []; foreach ($item['query_fields'] as $query_field) { $query_fields[] = [$query_field['name'] => $query_field['value']]; } $item['query_fields'] = $query_fields; } foreach ($item['preprocessing'] as &$preprocessing_step) { $preprocessing_step['params'] = implode("\n", $preprocessing_step['parameters']); unset($preprocessing_step['parameters']); } unset($preprocessing_step); $itemsId = $this->referencer->resolveItem($hostId, $item['key_']); if ($itemsId) { $item['itemid'] = $itemsId; if (!array_key_exists($level, $items_to_update)) { $items_to_update[$level] = []; } $items_to_update[$level][] = $item; } else { if (!array_key_exists($level, $items_to_create)) { $items_to_create[$level] = []; } $items_to_create[$level][] = $item; } } } // create/update the items and create a hash hostid->key_->itemid if ($this->options['items']['createMissing'] && $items_to_create) { $this->createEntitiesWithDependency($xml_itemkey, $items_to_create, API::Item()); } if ($this->options['items']['updateExisting'] && $items_to_update) { $this->updateEntitiesWithDependency($xml_itemkey, $items_to_update, API::Item()); } // refresh items because templated ones can be inherited to host and used in triggers, graphs, etc. $this->referencer->refreshItems(); } /** * Create CItem or CItemPrototype with dependency. * * @param string $xml_entitykey Master entity array key in xml parsed data. * @param array $entities_by_level Associative array of entities where key is entity dependency * level and value is array of entities for this level. * @param CItem|CItemPrototype $entity_service Entity service which is capable to proceed with entity create. * * @throws Exception if entity master entity can not be resolved. */ protected function createEntitiesWithDependency($xml_entitykey, $entities_by_level, $entity_service) { foreach ($entities_by_level as $level => $entities) { foreach ($entities as &$entity) { if (array_key_exists($xml_entitykey, $entity)) { $entity['master_itemid'] = $this->referencer->resolveItem($entity['hostid'], $entity[$xml_entitykey]['key'] ); if ($entity['master_itemid'] === false) { throw new Exception(_s('Incorrect value for field "%1$s": %2$s.', 'master_itemid', _s('value "%1$s" not found', $entity[$xml_entitykey]['key']) )); } unset($entity[$xml_entitykey]); } } unset($entity); $entityids = $entity_service->create($entities)['itemids']; $entityid = reset($entityids); foreach ($entities as $entity) { $this->referencer->addItemRef($entity['hostid'], $entity['key_'], $entityid); $entityid = next($entityids); } } } /** * Update CItem or CItemPrototype with dependency. * * @param string $xml_entitykey Master entity array key in xml parsed data. * @param array $entities_by_level Associative array of entities where key is entity dependency * level and value is array of entities for this level. * @param CItem|CItemPrototype $entity_service Entity service which is capable to proceed with entity update. * * @throws Exception if entity master entity can not be resolved. */ protected function updateEntitiesWithDependency($xml_entitykey, $entities_by_level, $entity_service) { foreach ($entities_by_level as $level => $entities) { foreach ($entities as &$entity) { if (array_key_exists($xml_entitykey, $entity)) { $entity['master_itemid'] = $this->referencer->resolveItem($entity['hostid'], $entity[$xml_entitykey]['key'] ); if ($entity['master_itemid'] === false) { throw new Exception(_s('Incorrect value for field "%1$s": %2$s.', 'master_itemid', _s('value "%1$s" not found', $entity[$xml_entitykey]['key']) )); } unset($entity[$xml_entitykey]); } } unset($entity); $entityids = $entity_service->update($entities)['itemids']; $entityid = reset($entityids); foreach ($entities as $entity) { $this->referencer->addItemRef($entity['hostid'], $entity['key_'], $entityid); $entityid = next($entityids); } } } /** * Import discovery rules. * * @throws Exception */ protected function processDiscoveryRules() { if (!$this->options['discoveryRules']['createMissing'] && !$this->options['discoveryRules']['updateExisting']) { return; } $allDiscoveryRules = $this->getFormattedDiscoveryRules(); if (!$allDiscoveryRules) { return; } // unset rules that are related to hosts we did not process foreach ($allDiscoveryRules as $host => $discoveryRules) { $hostId = $this->referencer->resolveHostOrTemplate($host); if (!$this->importedObjectContainer->isHostProcessed($hostId) && !$this->importedObjectContainer->isTemplateProcessed($hostId)) { unset($allDiscoveryRules[$host]); } } if ($this->options['discoveryRules']['updateExisting']) { $this->deleteMissingPrototypes($allDiscoveryRules); } $itemsToCreate = []; $itemsToUpdate = []; foreach ($allDiscoveryRules as $host => $discoveryRules) { $hostId = $this->referencer->resolveHostOrTemplate($host); foreach ($discoveryRules as $item) { $item['hostid'] = $hostId; if (array_key_exists('interface_ref', $item) && $item['interface_ref']) { $interfaceid = $this->referencer->resolveInterface($hostId, $item['interface_ref']); if ($interfaceid) { $item['interfaceid'] = $interfaceid; } else { throw new Exception(_s('Cannot find interface "%1$s" used for discovery rule "%2$s" on "%3$s".', $item['interface_ref'], $item['name'], $host )); } } unset($item['item_prototypes']); unset($item['trigger_prototypes']); unset($item['graph_prototypes']); unset($item['host_prototypes']); $itemId = $this->referencer->resolveItem($hostId, $item['key_']); if ($item['type'] == ITEM_TYPE_HTTPAGENT) { $headers = []; foreach ($item['headers'] as $header) { $headers[$header['name']] = $header['value']; } $item['headers'] = $headers; $query_fields = []; foreach ($item['query_fields'] as $query_field) { $query_fields[] = [$query_field['name'] => $query_field['value']]; } $item['query_fields'] = $query_fields; } if ($item['type'] == ITEM_TYPE_DEPENDENT) { if (!array_key_exists('key', $item['master_item'])) { throw new Exception( _s('Incorrect value for field "%1$s": %2$s.', 'master_itemid', _('cannot be empty') )); } $item['master_itemid'] = $this->referencer->resolveItem($hostId, $item['master_item']['key']); } unset($item['master_item']); if ($item['overrides']) { foreach ($item['overrides'] as &$override) { foreach ($override['operations'] as &$operation) { if ($operation['operationobject'] == OPERATION_OBJECT_HOST_PROTOTYPE && array_key_exists('optemplate', $operation)) { foreach ($operation['optemplate'] as &$template) { $templateid = $this->referencer->resolveTemplate($template['name']); if (!$templateid) { throw new Exception(_s( 'Cannot find template "%1$s" for override "%2$s" of discovery rule "%3$s" on "%4$s".', $template['name'], $override['name'], $item['name'], $host )); } $template['templateid'] = $templateid; unset($template['name']); } } } unset($operation); } unset($override); } foreach ($item['preprocessing'] as &$preprocessing_step) { $preprocessing_step['params'] = implode("\n", $preprocessing_step['parameters']); unset($preprocessing_step['parameters']); } unset($preprocessing_step); if ($itemId) { $item['itemid'] = $itemId; $itemsToUpdate[] = $item; } else { /* * The array key "lld_macro_paths" must exist at this point. It is processed by chain conversion. * Unlike discoveryrule.update method, discoveryrule.create does not allow "lld_macro_paths" * to be empty. */ if (!$item['lld_macro_paths']) { unset($item['lld_macro_paths']); } $itemsToCreate[] = $item; } } } // create/update discovery rules and add processed rules to array $processedRules $processedRules = []; if ($this->options['discoveryRules']['createMissing'] && $itemsToCreate) { $newItemsIds = API::DiscoveryRule()->create($itemsToCreate); foreach ($newItemsIds['itemids'] as $inum => $itemid) { $item = $itemsToCreate[$inum]; $this->referencer->addItemRef($item['hostid'], $item['key_'], $itemid); } foreach ($itemsToCreate as $item) { $processedRules[$item['hostid']][$item['key_']] = 1; } } if ($this->options['discoveryRules']['updateExisting'] && $itemsToUpdate) { API::DiscoveryRule()->update($itemsToUpdate); foreach ($itemsToUpdate as $item) { $processedRules[$item['hostid']][$item['key_']] = 1; } } // refresh discovery rules because templated ones can be inherited to host and used for prototypes $this->referencer->refreshItems(); $xml_item_key = 'master_item'; $order_tree = $this->getDiscoveryRulesItemsOrder($xml_item_key); // process prototypes $prototypes_to_update = []; $prototypes_to_create = []; $host_prototypes_to_update = []; $hostPrototypesToCreate = []; $ex_group_prototypes_where = []; foreach ($allDiscoveryRules as $host => $discoveryRules) { $hostId = $this->referencer->resolveHostOrTemplate($host); foreach ($discoveryRules as $item) { // if rule was not processed we should not create/update any of its prototypes if (!isset($processedRules[$hostId][$item['key_']])) { continue; } $item['hostid'] = $hostId; $item_key = $item['key_']; $itemId = $this->referencer->resolveItem($hostId, $item_key); // prototypes $item_prototypes = $item['item_prototypes'] ? $order_tree[$host][$item_key] : []; foreach ($item_prototypes as $index => $level) { $prototype = $item['item_prototypes'][$index]; $prototype['hostid'] = $hostId; $applicationsIds = []; foreach ($prototype['applications'] as $application) { $applicationsIds[] = $this->referencer->resolveApplication($hostId, $application['name']); } $prototype['applications'] = $applicationsIds; if (array_key_exists('application_prototypes', $prototype)) { $prototype['applicationPrototypes'] = $prototype['application_prototypes']; } if (array_key_exists('interface_ref', $prototype) && $prototype['interface_ref']) { $interfaceid = $this->referencer->resolveInterface($hostId, $prototype['interface_ref']); if ($interfaceid) { $prototype['interfaceid'] = $interfaceid; } else { throw new Exception(_s( 'Cannot find interface "%1$s" used for item prototype "%2$s" of discovery rule "%3$s" on "%4$s".', $prototype['interface_ref'], $prototype['name'], $item['name'], $host )); } } if ($prototype['valuemap']) { $valueMapId = $this->referencer->resolveValueMap($prototype['valuemap']['name']); if (!$valueMapId) { throw new Exception(_s( 'Cannot find value map "%1$s" used for item prototype "%2$s" of discovery rule "%3$s" on "%4$s".', $prototype['valuemap']['name'], $prototype['name'], $item['name'], $host )); } $prototype['valuemapid'] = $valueMapId; } if ($prototype['type'] == ITEM_TYPE_DEPENDENT) { if (!array_key_exists('key', $prototype[$xml_item_key])) { throw new Exception( _s('Incorrect value for field "%1$s": %2$s.', 'master_itemid', _('cannot be empty') )); } $master_itemprototypeid = $this->referencer->resolveItem($hostId, $prototype[$xml_item_key]['key'] ); if ($master_itemprototypeid !== false) { $prototype['master_itemid'] = $master_itemprototypeid; unset($prototype[$xml_item_key]); } } else { unset($prototype[$xml_item_key]); } if ($prototype['type'] == ITEM_TYPE_HTTPAGENT) { $headers = []; foreach ($prototype['headers'] as $header) { $headers[$header['name']] = $header['value']; } $prototype['headers'] = $headers; $query_fields = []; foreach ($prototype['query_fields'] as $query_field) { $query_fields[] = [$query_field['name'] => $query_field['value']]; } $prototype['query_fields'] = $query_fields; } $prototypeId = $this->referencer->resolveItem($hostId, $prototype['key_']); $prototype['rule'] = ['hostid' => $hostId, 'key' => $item['key_']]; $prototype['ruleid'] = $this->referencer->resolveItem($hostId, $item['key_']); foreach ($prototype['preprocessing'] as &$preprocessing_step) { $preprocessing_step['params'] = implode("\n", $preprocessing_step['parameters']); unset($preprocessing_step['parameters']); } unset($preprocessing_step); if ($prototypeId) { if (!array_key_exists($level, $prototypes_to_update)) { $prototypes_to_update[$level] = []; } $prototype['itemid'] = $prototypeId; $prototypes_to_update[$level][] = $prototype; } else { if (!array_key_exists($level, $prototypes_to_create)) { $prototypes_to_create[$level] = []; } $prototypes_to_create[$level][] = $prototype; } } // host prototype foreach ($item['host_prototypes'] as $hostPrototype) { // resolve group prototypes $groupLinks = []; foreach ($hostPrototype['group_links'] as $groupLink) { $groupId = $this->referencer->resolveGroup($groupLink['group']['name']); if (!$groupId) { throw new Exception(_s( 'Cannot find host group "%1$s" for host prototype "%2$s" of discovery rule "%3$s" on "%4$s".', $groupLink['group']['name'], $hostPrototype['name'], $item['name'], $host )); } $groupLinks[] = ['groupid' => $groupId]; } $hostPrototype['groupLinks'] = $groupLinks; $hostPrototype['groupPrototypes'] = $hostPrototype['group_prototypes']; unset($hostPrototype['group_links'], $hostPrototype['group_prototypes']); // resolve templates $templates = []; foreach ($hostPrototype['templates'] as $template) { $templateId = $this->referencer->resolveTemplate($template['name']); if (!$templateId) { throw new Exception(_s( 'Cannot find template "%1$s" for host prototype "%2$s" of discovery rule "%3$s" on "%4$s".', $template['name'], $hostPrototype['name'], $item['name'], $host )); } $templates[] = ['templateid' => $templateId]; } $hostPrototype['templates'] = $templates; $hostPrototypeId = $this->referencer->resolveHostPrototype($hostId, $itemId, $hostPrototype['host']); if ($hostPrototypeId) { if ($hostPrototype['groupPrototypes']) { $ex_group_prototypes_where[] = '('.dbConditionInt('hostid', [$hostPrototypeId]). ' AND '.dbConditionString('name', zbx_objectValues($hostPrototype['groupPrototypes'], 'name') ). ')'; } $hostPrototype['hostid'] = $hostPrototypeId; $host_prototypes_to_update[] = $hostPrototype; } else { $hostPrototype['ruleid'] = $itemId; $hostPrototypesToCreate[] = $hostPrototype; } } } } // Attach existing host group prototype ids. if ($ex_group_prototypes_where) { $db_group_prototypes = DBFetchArray(DBselect( 'SELECT group_prototypeid,name,hostid'. ' FROM group_prototype'. ' WHERE '.implode(' OR ', $ex_group_prototypes_where) )); if ($db_group_prototypes) { $groups_hash = []; foreach ($db_group_prototypes as $group) { $groups_hash[$group['hostid']][$group['name']] = $group['group_prototypeid']; } foreach ($host_prototypes_to_update as &$host_prototype) { if (!array_key_exists($host_prototype['hostid'], $groups_hash)) { continue; } $hash = $groups_hash[$host_prototype['hostid']]; foreach ($host_prototype['groupPrototypes'] as &$group_prototype) { if (array_key_exists($group_prototype['name'], $hash)) { $group_prototype['group_prototypeid'] = $hash[$group_prototype['name']]; } } unset($group_prototype, $hash); } unset($host_prototype, $groups_hash); } } if ($prototypes_to_create) { ksort($prototypes_to_create); $this->createEntitiesWithDependency($xml_item_key, $prototypes_to_create, API::ItemPrototype()); } if ($prototypes_to_update) { ksort($prototypes_to_update); $this->updateEntitiesWithDependency($xml_item_key, $prototypes_to_update, API::ItemPrototype()); } if ($hostPrototypesToCreate) { API::HostPrototype()->create($hostPrototypesToCreate); } if ($host_prototypes_to_update) { API::HostPrototype()->update($host_prototypes_to_update); } // refresh prototypes because templated ones can be inherited to host and used in triggers prototypes or graph prototypes $this->referencer->refreshItems(); // first we need to create item prototypes and only then graph prototypes $triggersToCreate = []; $triggersToUpdate = []; $graphsToCreate = []; $graphsToUpdate = []; // the list of triggers to process dependencies $triggers = []; foreach ($allDiscoveryRules as $host => $discoveryRules) { $hostId = $this->referencer->resolveHostOrTemplate($host); foreach ($discoveryRules as $item) { // if rule was not processed we should not create/update any of its prototypes if (!isset($processedRules[$hostId][$item['key_']])) { continue; } // trigger prototypes foreach ($item['trigger_prototypes'] as $trigger) { $triggerId = $this->referencer->resolveTrigger($trigger['description'], $trigger['expression'], $trigger['recovery_expression'] ); $triggers[] = $trigger; unset($trigger['dependencies']); if ($triggerId) { $trigger['triggerid'] = $triggerId; $triggersToUpdate[] = $trigger; } else { $triggersToCreate[] = $trigger; } } // graph prototypes foreach ($item['graph_prototypes'] as $graph) { if ($graph['ymin_item_1']) { $hostId = $this->referencer->resolveHostOrTemplate($graph['ymin_item_1']['host']); $itemId = $hostId ? $this->referencer->resolveItem($hostId, $graph['ymin_item_1']['key']) : false; if (!$itemId) { throw new Exception(_s( 'Cannot find item "%1$s" on "%2$s" used as the Y axis MIN value for graph prototype "%3$s" of discovery rule "%4$s" on "%5$s".', $graph['ymin_item_1']['key'], $graph['ymin_item_1']['host'], $graph['name'], $item['name'], $host )); } $graph['ymin_itemid'] = $itemId; } if ($graph['ymax_item_1']) { $hostId = $this->referencer->resolveHostOrTemplate($graph['ymax_item_1']['host']); $itemId = $hostId ? $this->referencer->resolveItem($hostId, $graph['ymax_item_1']['key']) : false; if (!$itemId) { throw new Exception(_s( 'Cannot find item "%1$s" on "%2$s" used as the Y axis MAX value for graph prototype "%3$s" of discovery rule "%4$s" on "%5$s".', $graph['ymax_item_1']['key'], $graph['ymax_item_1']['host'], $graph['name'], $item['name'], $host )); } $graph['ymax_itemid'] = $itemId; } foreach ($graph['gitems'] as &$gitem) { $gitemHostId = $this->referencer->resolveHostOrTemplate($gitem['item']['host']); $gitem['itemid'] = $gitemHostId ? $this->referencer->resolveItem($gitemHostId, $gitem['item']['key']) : false; if (!$gitem['itemid']) { throw new Exception(_s( 'Cannot find item "%1$s" on "%2$s" used in graph prototype "%3$s" of discovery rule "%4$s" on "%5$s".', $gitem['item']['key'], $gitem['item']['host'], $graph['name'], $item['name'], $host )); } } unset($gitem); $graphId = $this->referencer->resolveGraph($gitemHostId, $graph['name']); if ($graphId) { $graph['graphid'] = $graphId; $graphsToUpdate[] = $graph; } else { $graphsToCreate[] = $graph; } } } } if ($triggersToCreate) { $result = API::TriggerPrototype()->create($triggersToCreate); foreach ($result['triggerids'] as $tnum => $triggerid) { $trigger = $triggersToCreate[$tnum]; $this->referencer->addTriggerRef($trigger['description'], $trigger['expression'], $trigger['recovery_expression'], $triggerid ); } } if ($triggersToUpdate) { API::TriggerPrototype()->update($triggersToUpdate); } if ($graphsToCreate) { API::GraphPrototype()->create($graphsToCreate); $this->referencer->refreshGraphs(); } if ($graphsToUpdate) { API::GraphPrototype()->update($graphsToUpdate); } $this->processTriggerPrototypeDependencies($triggers); } /** * Update trigger dependencies * * @param array $triggers * * @throws Exception */ protected function processTriggerPrototypeDependencies(array $triggers) { $dependencies = []; foreach ($triggers as $trigger) { if (!array_key_exists('dependencies', $trigger)) { continue; } $deps = []; $triggerid = $this->referencer->resolveTrigger($trigger['description'], $trigger['expression'], $trigger['recovery_expression'] ); foreach ($trigger['dependencies'] as $dependency) { $dep_triggerid = $this->referencer->resolveTrigger($dependency['name'], $dependency['expression'], $dependency['recovery_expression'] ); if (!$dep_triggerid) { throw new Exception(_s('Trigger prototype "%1$s" depends on trigger "%2$s", which does not exist.', $trigger['description'], $dependency['name'] )); } $deps[] = ['triggerid' => $dep_triggerid]; } $dependencies[] = [ 'triggerid' => $triggerid, 'dependencies' => $deps ]; } if ($dependencies) { API::TriggerPrototype()->update($dependencies); } } /** * Import web scenarios. */ protected function processHttpTests() { if (!$this->options['httptests']['createMissing'] && !$this->options['httptests']['updateExisting']) { return; } $all_httptests = $this->getFormattedHttpTests(); if (!$all_httptests) { return; } $httptests_to_create = []; $httptests_to_update = []; foreach ($all_httptests as $host => $httptests) { $hostid = $this->referencer->resolveHostOrTemplate($host); if (!$this->importedObjectContainer->isHostProcessed($hostid) && !$this->importedObjectContainer->isTemplateProcessed($hostid)) { continue; } foreach ($httptests as $httptest) { if (array_key_exists('name', $httptest['application'])) { $applicationid = $this->referencer->resolveApplication($hostid, $httptest['application']['name']); if ($applicationid === false) { throw new Exception(_s('Web scenario "%1$s" on "%2$s": application "%3$s" does not exist.', $httptest['name'], $host, $httptest['application']['name'])); } $httptest['applicationid'] = $applicationid; } else { $httptest['applicationid'] = 0; } unset($httptest['application']); $httptestid = $this->referencer->resolveHttpTest($hostid, $httptest['name']); if ($httptestid !== false) { foreach ($httptest['steps'] as &$httpstep) { $httpstepid = $this->referencer->resolveHttpStep($hostid, $httptestid, $httpstep['name']); if ($httpstepid !== false) { $httpstep['httpstepid'] = $httpstepid; } } unset($httpstep); $httptest['httptestid'] = $httptestid; $httptests_to_update[] = $httptest; } else { $httptest['hostid'] = $hostid; $httptests_to_create[] = $httptest; } } } // create/update web scenarios and create a hash hostid->name->httptestid if ($this->options['httptests']['createMissing'] && $httptests_to_create) { API::HttpTest()->create($httptests_to_create); } if ($this->options['httptests']['updateExisting'] && $httptests_to_update) { API::HttpTest()->update($httptests_to_update); } $this->referencer->refreshHttpTests(); } /** * Import graphs. * * @throws Exception */ protected function processGraphs() { if (!$this->options['graphs']['createMissing'] && !$this->options['graphs']['updateExisting']) { return; } $allGraphs = $this->getFormattedGraphs(); if (!$allGraphs) { return; } $graphsToCreate = []; $graphsToUpdate = []; foreach ($allGraphs as $graph) { if ($graph['ymin_item_1']) { $hostId = $this->referencer->resolveHostOrTemplate($graph['ymin_item_1']['host']); $itemId = $hostId ? $this->referencer->resolveItem($hostId, $graph['ymin_item_1']['key']) : false; if (!$itemId) { throw new Exception(_s( 'Cannot find item "%1$s" on "%2$s" used as the Y axis MIN value for graph "%3$s".', $graph['ymin_item_1']['key'], $graph['ymin_item_1']['host'], $graph['name'] )); } $graph['ymin_itemid'] = $itemId; } if ($graph['ymax_item_1']) { $hostId = $this->referencer->resolveHostOrTemplate($graph['ymax_item_1']['host']); $itemId = $hostId ? $this->referencer->resolveItem($hostId, $graph['ymax_item_1']['key']) : false; if (!$itemId) { throw new Exception(_s( 'Cannot find item "%1$s" on "%2$s" used as the Y axis MAX value for graph "%3$s".', $graph['ymax_item_1']['key'], $graph['ymax_item_1']['host'], $graph['name'] )); } $graph['ymax_itemid'] = $itemId; } foreach ($graph['gitems'] as &$gitem) { $gitemHostId = $this->referencer->resolveHostOrTemplate($gitem['item']['host']); $gitem['itemid'] = $gitemHostId ? $this->referencer->resolveItem($gitemHostId, $gitem['item']['key']) : false; if (!$gitem['itemid']) { throw new Exception(_s( 'Cannot find item "%1$s" on "%2$s" used in graph "%3$s".', $gitem['item']['key'], $gitem['item']['host'], $graph['name'] )); } } unset($gitem); $graphId = $this->referencer->resolveGraph($gitemHostId, $graph['name']); if ($graphId) { $graph['graphid'] = $graphId; $graphsToUpdate[] = $graph; } else { $graphsToCreate[] = $graph; } } if ($this->options['graphs']['createMissing'] && $graphsToCreate) { API::Graph()->create($graphsToCreate); } if ($this->options['graphs']['updateExisting'] && $graphsToUpdate) { API::Graph()->update($graphsToUpdate); } $this->referencer->refreshGraphs(); } /** * Import triggers. */ protected function processTriggers() { if (!$this->options['triggers']['createMissing'] && !$this->options['triggers']['updateExisting']) { return; } $allTriggers = $this->getFormattedTriggers(); if (!$allTriggers) { return; } $triggersToCreate = []; $triggersToUpdate = []; // the list of triggers to process dependencies $triggers = []; foreach ($allTriggers as $trigger) { $triggerId = $this->referencer->resolveTrigger($trigger['description'], $trigger['expression'], $trigger['recovery_expression'] ); if ($triggerId) { if ($this->options['triggers']['updateExisting']) { $triggers[] = $trigger; $trigger['triggerid'] = $triggerId; unset($trigger['dependencies']); $triggersToUpdate[] = $trigger; } } else { if ($this->options['triggers']['createMissing']) { $triggers[] = $trigger; unset($trigger['dependencies']); $triggersToCreate[] = $trigger; } } } if ($triggersToCreate) { $result = API::Trigger()->create($triggersToCreate); foreach ($result['triggerids'] as $tnum => $triggerid) { $trigger = $triggersToCreate[$tnum]; $this->referencer->addTriggerRef($trigger['description'], $trigger['expression'], $trigger['recovery_expression'], $triggerid ); } } if ($triggersToUpdate) { API::Trigger()->update($triggersToUpdate); } // refresh triggers because template triggers can be inherited to host and used in maps $this->referencer->refreshTriggers(); $this->processTriggerDependencies($triggers); } /** * Update trigger dependencies * * @param array $triggers * * @throws Exception */ protected function processTriggerDependencies(array $triggers) { $dependencies = []; foreach ($triggers as $trigger) { if (!array_key_exists('dependencies', $trigger)) { continue; } $deps = []; $triggerid = $this->referencer->resolveTrigger($trigger['description'], $trigger['expression'], $trigger['recovery_expression'] ); foreach ($trigger['dependencies'] as $dependency) { $dep_triggerid = $this->referencer->resolveTrigger($dependency['name'], $dependency['expression'], $dependency['recovery_expression'] ); if (!$dep_triggerid) { throw new Exception(_s('Trigger "%1$s" depends on trigger "%2$s", which does not exist.', $trigger['description'], $dependency['name'] )); } $deps[] = ['triggerid' => $dep_triggerid]; } $dependencies[] = [ 'triggerid' => $triggerid, 'dependencies' => $deps ]; } if ($dependencies) { API::Trigger()->update($dependencies); } } /** * Import images. * * @throws Exception * * @return null */ protected function processImages() { if (!$this->options['images']['updateExisting'] && !$this->options['images']['createMissing']) { return; } $allImages = $this->getFormattedImages(); if (!$allImages) { return; } $allImages = zbx_toHash($allImages, 'name'); $dbImages = API::Image()->get([ 'output' => ['imageid', 'name'], 'filter' => ['name' => array_keys($allImages)] ]); $dbImages = zbx_toHash($dbImages, 'name'); $imagesToUpdate = []; $imagesToCreate = []; foreach ($allImages as $imageName => $image) { if (isset($dbImages[$imageName])) { $image['imageid'] = $dbImages[$imageName]['imageid']; unset($image['imagetype']); $imagesToUpdate[] = $image; } else { $imagesToCreate[] = $image; } } if ($this->options['images']['createMissing'] && $imagesToCreate) { API::Image()->create($imagesToCreate); } if ($this->options['images']['updateExisting'] && $imagesToUpdate) { API::Image()->update($imagesToUpdate); } } /** * Import maps. */ protected function processMaps() { if ($this->options['maps']['updateExisting'] || $this->options['maps']['createMissing']) { $maps = $this->getFormattedMaps(); if ($maps) { $mapImporter = new CMapImporter($this->options, $this->referencer, $this->importedObjectContainer); $mapImporter->import($maps); } } } /** * Import screens. */ protected function processScreens() { if ($this->options['screens']['updateExisting'] || $this->options['screens']['createMissing']) { $screens = $this->getFormattedScreens(); if ($screens) { $screenImporter = new CScreenImporter($this->options, $this->referencer, $this->importedObjectContainer ); $screenImporter->import($screens); } } } /** * Import template dashboards. */ protected function processTemplateDashboards() { if ($this->options['templateDashboards']['updateExisting'] || $this->options['templateDashboards']['createMissing'] || $this->options['templateDashboards']['deleteMissing']) { $dashboards = $this->getFormattedTemplateDashboards(); $dashboardImporter = new CTemplateDashboardImporter($this->options, $this->referencer, $this->importedObjectContainer ); $dashboardImporter->delete($dashboards); $dashboardImporter->import($dashboards); } } /** * Import media types. */ protected function processMediaTypes() { if (!$this->options['mediaTypes']['updateExisting'] && !$this->options['mediaTypes']['createMissing']) { return; } $all_media_types = $this->getFormattedMediaTypes(); if (!$all_media_types) { return; } $all_media_types = zbx_toHash($all_media_types, 'name'); $db_media_types = API::MediaType()->get([ 'output' => ['mediatypeid', 'name'], 'filter' => ['name' => array_keys($all_media_types)] ]); $db_media_types = zbx_toHash($db_media_types, 'name'); $upd_media_types = []; $new_media_types = []; foreach ($all_media_types as $name => $media_type) { if (array_key_exists($name, $db_media_types)) { $media_type['mediatypeid'] = $db_media_types[$name]['mediatypeid']; $upd_media_types[] = $media_type; } else { $new_media_types[] = $media_type; } } if ($this->options['mediaTypes']['createMissing'] && $new_media_types) { API::MediaType()->create($new_media_types); } if ($this->options['mediaTypes']['updateExisting'] && $upd_media_types) { API::MediaType()->update($upd_media_types); } } /** * Deletes items from DB that are missing in XML. * * @return null */ protected function deleteMissingItems() { if (!$this->options['items']['deleteMissing']) { return; } $processedHostIds = $this->importedObjectContainer->getHostIds(); $processedTemplateIds = $this->importedObjectContainer->getTemplateIds(); $processedHostIds = array_merge($processedHostIds, $processedTemplateIds); // no hosts or templates have been processed if (!$processedHostIds) { return; } $itemIdsXML = []; $allItems = $this->getFormattedItems(); if ($allItems) { foreach ($allItems as $host => $items) { $hostId = $this->referencer->resolveHostOrTemplate($host); foreach ($items as $item) { $itemId = $this->referencer->resolveItem($hostId, $item['key_']); if ($itemId) { $itemIdsXML[$itemId] = $itemId; } } } } $dbItemIds = API::Item()->get([ 'output' => ['itemid'], 'hostids' => $processedHostIds, 'preservekeys' => true, 'nopermissions' => true, 'inherited' => false, 'filter' => ['flags' => ZBX_FLAG_DISCOVERY_NORMAL] ]); $itemsToDelete = array_diff_key($dbItemIds, $itemIdsXML); if ($itemsToDelete) { API::Item()->delete(array_keys($itemsToDelete)); } $this->referencer->refreshItems(); } /** * Deletes applications from DB that are missing in XML. * * @return null */ protected function deleteMissingApplications() { if (!$this->options['applications']['deleteMissing']) { return; } $processedHostIds = $this->importedObjectContainer->getHostIds(); $processedTemplateIds = $this->importedObjectContainer->getTemplateIds(); $processedHostIds = array_merge($processedHostIds, $processedTemplateIds); // no hosts or templates have been processed if (!$processedHostIds) { return; } $applicationIdsXML = []; $allApplications = $this->getFormattedApplications(); if ($allApplications) { foreach ($allApplications as $host => $applications) { $hostId = $this->referencer->resolveHostOrTemplate($host); foreach ($applications as $application) { $applicationId = $this->referencer->resolveApplication($hostId, $application['name']); if ($applicationId) { $applicationIdsXML[$applicationId] = $applicationId; } } } } $dbApplicationIds = API::Application()->get([ 'output' => ['applicationid'], 'hostids' => $processedHostIds, 'preservekeys' => true, 'nopermissions' => true, 'inherited' => false, 'filter' => ['flags' => ZBX_FLAG_DISCOVERY_NORMAL] ]); $applicationsToDelete = array_diff_key($dbApplicationIds, $applicationIdsXML); if ($applicationsToDelete) { API::Application()->delete(array_keys($applicationsToDelete)); } // refresh applications because templated ones can be inherited to host and used in items $this->referencer->refreshApplications(); } /** * Deletes triggers from DB that are missing in XML. * * @return null */ protected function deleteMissingTriggers() { if (!$this->options['triggers']['deleteMissing']) { return; } $processedHostIds = $this->importedObjectContainer->getHostIds(); $processedTemplateIds = $this->importedObjectContainer->getTemplateIds(); $processedHostIds = array_merge($processedHostIds, $processedTemplateIds); // no hosts or templates have been processed if (!$processedHostIds) { return; } $triggersXML = []; $allTriggers = $this->getFormattedTriggers(); if ($allTriggers) { foreach ($allTriggers as $trigger) { $triggerId = $this->referencer->resolveTrigger($trigger['description'], $trigger['expression'], $trigger['recovery_expression'] ); if ($triggerId) { $triggersXML[$triggerId] = $triggerId; } } } $dbTriggerIds = API::Trigger()->get([ 'output' => ['triggerid'], 'hostids' => $processedHostIds, 'selectHosts' => ['hostid'], 'preservekeys' => true, 'nopermissions' => true, 'inherited' => false, 'filter' => ['flags' => ZBX_FLAG_DISCOVERY_NORMAL] ]); // check that potentially deletable trigger belongs to same hosts that are in XML // if some triggers belong to more hosts than current XML contains, don't delete them $triggersToDelete = array_diff_key($dbTriggerIds, $triggersXML); $triggerIdsToDelete = []; $processedHostIds = array_flip($processedHostIds); foreach ($triggersToDelete as $triggerId => $trigger) { $triggerHostIds = array_flip(zbx_objectValues($trigger['hosts'], 'hostid')); if (!array_diff_key($triggerHostIds, $processedHostIds)) { $triggerIdsToDelete[] = $triggerId; } } if ($triggerIdsToDelete) { API::Trigger()->delete($triggerIdsToDelete); } // refresh triggers because template triggers can be inherited to host and used in maps $this->referencer->refreshTriggers(); } /** * Deletes graphs from DB that are missing in XML. * * @return null */ protected function deleteMissingGraphs() { if (!$this->options['graphs']['deleteMissing']) { return; } $processedHostIds = $this->importedObjectContainer->getHostIds(); $processedTemplateIds = $this->importedObjectContainer->getTemplateIds(); $processedHostIds = array_merge($processedHostIds, $processedTemplateIds); // no hosts or templates have been processed if (!$processedHostIds) { return; } $graphsIdsXML = []; // gather host IDs for graphs that exist in XML $allGraphs = $this->getFormattedGraphs(); if ($allGraphs) { foreach ($allGraphs as $graph) { if (isset($graph['gitems']) && $graph['gitems']) { foreach ($graph['gitems'] as $gitem) { $gitemHostId = $this->referencer->resolveHostOrTemplate($gitem['item']['host']); $graphId = $this->referencer->resolveGraph($gitemHostId, $graph['name']); if ($graphId) { $graphsIdsXML[$graphId] = $graphId; } } } } } $dbGraphIds = API::Graph()->get([ 'output' => ['graphid'], 'hostids' => $processedHostIds, 'selectHosts' => ['hostid'], 'preservekeys' => true, 'nopermissions' => true, 'inherited' => false, 'filter' => ['flags' => ZBX_FLAG_DISCOVERY_NORMAL] ]); // check that potentially deletable graph belongs to same hosts that are in XML // if some graphs belong to more hosts than current XML contains, don't delete them $graphsToDelete = array_diff_key($dbGraphIds, $graphsIdsXML); $graphIdsToDelete = []; $processedHostIds = array_flip($processedHostIds); foreach ($graphsToDelete as $graphId => $graph) { $graphHostIds = array_flip(zbx_objectValues($graph['hosts'], 'hostid')); if (!array_diff_key($graphHostIds, $processedHostIds)) { $graphIdsToDelete[] = $graphId; } } if ($graphIdsToDelete) { API::Graph()->delete($graphIdsToDelete); } $this->referencer->refreshGraphs(); } /** * Deletes discovery rules from DB that are missing in XML. * * @return null */ protected function deleteMissingDiscoveryRules() { if (!$this->options['discoveryRules']['deleteMissing']) { return; } $processedHostIds = $this->importedObjectContainer->getHostIds(); $processedTemplateIds = $this->importedObjectContainer->getTemplateIds(); $processedHostIds = array_merge($processedHostIds, $processedTemplateIds); // no hosts or templates have been processed if (!$processedHostIds) { return; } $discoveryRuleIdsXML = []; $allDiscoveryRules = $this->getFormattedDiscoveryRules(); foreach ($allDiscoveryRules as $host => $discoveryRules) { $hostId = $this->referencer->resolveHostOrTemplate($host); foreach ($discoveryRules as $discoveryRule) { $discoveryRuleId = $this->referencer->resolveItem($hostId, $discoveryRule['key_']); if ($discoveryRuleId) { $discoveryRuleIdsXML[$discoveryRuleId] = $discoveryRuleId; } } } $dbDiscoveryRuleIds = API::DiscoveryRule()->get([ 'output' => ['itemid'], 'hostids' => $processedHostIds, 'preservekeys' => true, 'nopermissions' => true, 'inherited' => false ]); $discoveryRulesToDelete = array_diff_key($dbDiscoveryRuleIds, $discoveryRuleIdsXML); if ($discoveryRulesToDelete) { API::DiscoveryRule()->delete(array_keys($discoveryRulesToDelete)); } // refresh discovery rules because templated ones can be inherited to host and used for prototypes $this->referencer->refreshItems(); } /** * Deletes prototypes from DB that are missing in XML. * * @param array $all_discovery_rules */ protected function deleteMissingPrototypes(array $all_discovery_rules) { $xml_discoveryids = []; $xml_host_prototypeids = []; $xml_trigger_prototypeids = []; $xml_graph_prototypeids = []; $xml_item_prototypeids = []; foreach ($all_discovery_rules as $host => $discovery_rules) { $hostid = $this->referencer->resolveHostOrTemplate($host); foreach ($discovery_rules as $discovery_rule) { $discoveryid = $this->referencer->resolveItem($hostid, $discovery_rule['key_']); if ($discoveryid) { $xml_discoveryids[$discoveryid] = $discoveryid; // gather host prototype IDs to delete foreach ($discovery_rule['host_prototypes'] as $host_prototype) { $host_prototypeid = $this->referencer->resolveHostPrototype($hostid, $discoveryid, $host_prototype['host'] ); if ($host_prototypeid) { $xml_host_prototypeids[$host_prototypeid] = $host_prototypeid; } } // gather trigger prototype IDs to delete foreach ($discovery_rule['trigger_prototypes'] as $trigger_prototype) { $trigger_prototypeid = $this->referencer->resolveTrigger($trigger_prototype['description'], $trigger_prototype['expression'], $trigger_prototype['recovery_expression'] ); if ($trigger_prototypeid) { $xml_trigger_prototypeids[$trigger_prototypeid] = $trigger_prototypeid; } } // gather graph prototype IDs to delete foreach ($discovery_rule['graph_prototypes'] as $graph_prototype) { $graph_prototypeid = $this->referencer->resolveGraph($hostid, $graph_prototype['name']); if ($graph_prototypeid) { $xml_graph_prototypeids[$graph_prototypeid] = $graph_prototypeid; } } // gather item prototype IDs to delete foreach ($discovery_rule['item_prototypes'] as $item_prototype) { $item_prototypeid = $this->referencer->resolveItem($hostid, $item_prototype['key_']); if ($item_prototypeid) { $xml_item_prototypeids[$item_prototypeid] = $item_prototypeid; } } } } } // delete missing host prototypes $db_host_prototypes = API::HostPrototype()->get([ 'output' => ['hostid'], 'discoveryids' => $xml_discoveryids, 'preservekeys' => true, 'nopermissions' => true, 'inherited' => false ]); $del_host_prototypes = array_diff_key($db_host_prototypes, $xml_host_prototypeids); if ($del_host_prototypes) { API::HostPrototype()->delete(array_keys($del_host_prototypes)); } // delete missing trigger prototypes $db_trigger_prototypes = API::TriggerPrototype()->get([ 'output' => ['triggerid'], 'discoveryids' => $xml_discoveryids, 'preservekeys' => true, 'nopermissions' => true, 'inherited' => false ]); $del_trigger_prototypes = array_diff_key($db_trigger_prototypes, $xml_trigger_prototypeids); // unlike triggers that belong to multiple hosts, trigger prototypes do not, so we just delete them if ($del_trigger_prototypes) { API::TriggerPrototype()->delete(array_keys($del_trigger_prototypes)); } // delete missing graph prototypes $db_graph_prototypes = API::GraphPrototype()->get([ 'output' => ['graphid'], 'discoveryids' => $xml_discoveryids, 'preservekeys' => true, 'nopermissions' => true, 'inherited' => false ]); $del_graph_prototypes = array_diff_key($db_graph_prototypes, $xml_graph_prototypeids); // unlike graphs that belong to multiple hosts, graph prototypes do not, so we just delete them if ($del_graph_prototypes) { API::GraphPrototype()->delete(array_keys($del_graph_prototypes)); } // delete missing item prototypes $db_item_prototypes = API::ItemPrototype()->get([ 'output' => ['itemid'], 'discoveryids' => $xml_discoveryids, 'preservekeys' => true, 'nopermissions' => true, 'inherited' => false ]); $del_item_prototypes = array_diff_key($db_item_prototypes, $xml_item_prototypeids); if ($del_item_prototypes) { API::ItemPrototype()->delete(array_keys($del_item_prototypes)); $this->referencer->refreshGraphs(); } } /** * Deletes web scenarios from DB that are missing in XML. */ protected function deleteMissingHttpTests() { if (!$this->options['httptests']['deleteMissing']) { return; } $processed_hostids = array_merge( $this->importedObjectContainer->getHostIds(), $this->importedObjectContainer->getTemplateIds() ); // no hosts or templates have been processed if (!$processed_hostids) { return; } $xml_httptestids = []; $all_httptests = $this->getFormattedHttpTests(); if ($all_httptests) { foreach ($all_httptests as $host => $httptests) { $hostid = $this->referencer->resolveHostOrTemplate($host); foreach ($httptests as $httptest) { $httptestid = $this->referencer->resolveHttpTest($hostid, $httptest['name']); if ($httptestid) { $xml_httptestids[$httptestid] = true; } } } } $db_httptestids = API::HttpTest()->get([ 'output' => [], 'hostids' => $processed_hostids, 'inherited' => false, 'preservekeys' => true, 'nopermissions' => true ]); $del_httptestids = array_diff_key($db_httptestids, $xml_httptestids); if ($del_httptestids) { API::HttpTest()->delete(array_keys($del_httptestids)); } $this->referencer->refreshHttpTests(); } /** * Get formatted groups. * * @return array */ protected function getFormattedGroups() { if (!isset($this->formattedData['groups'])) { $this->formattedData['groups'] = $this->adapter->getGroups(); } return $this->formattedData['groups']; } /** * Get formatted templates. * * @return array */ public function getFormattedTemplates() { if (!isset($this->formattedData['templates'])) { $this->formattedData['templates'] = $this->adapter->getTemplates(); } return $this->formattedData['templates']; } /** * Get formatted hosts. * * @return array */ public function getFormattedHosts() { if (!isset($this->formattedData['hosts'])) { $this->formattedData['hosts'] = $this->adapter->getHosts(); } return $this->formattedData['hosts']; } /** * Get formatted applications. * * @return array */ protected function getFormattedApplications() { if (!isset($this->formattedData['applications'])) { $this->formattedData['applications'] = $this->adapter->getApplications(); } return $this->formattedData['applications']; } /** * Get formatted value maps. * * @return array */ protected function getFormattedValueMaps() { if (!isset($this->formattedData['valueMaps'])) { $this->formattedData['valueMaps'] = $this->adapter->getValueMaps(); } return $this->formattedData['valueMaps']; } /** * Get formatted items. * * @return array */ protected function getFormattedItems() { if (!isset($this->formattedData['items'])) { $this->formattedData['items'] = $this->adapter->getItems(); } return $this->formattedData['items']; } /** * Get formatted discovery rules. * * @return array */ protected function getFormattedDiscoveryRules() { if (!isset($this->formattedData['discoveryRules'])) { $this->formattedData['discoveryRules'] = $this->adapter->getDiscoveryRules(); } return $this->formattedData['discoveryRules']; } /** * Get formatted web scenarios. * * @return array */ protected function getFormattedHttpTests() { if (!array_key_exists('httptests', $this->formattedData)) { $this->formattedData['httptests'] = $this->adapter->getHttpTests(); } return $this->formattedData['httptests']; } /** * Get formatted web scenario steps. * * @return array */ protected function getFormattedHttpSteps() { if (!array_key_exists('httpsteps', $this->formattedData)) { $this->formattedData['httpsteps'] = $this->adapter->getHttpSteps(); } return $this->formattedData['httpsteps']; } /** * Get formatted triggers. * * @return array */ protected function getFormattedTriggers() { if (!isset($this->formattedData['triggers'])) { $this->formattedData['triggers'] = $this->adapter->getTriggers(); } return $this->formattedData['triggers']; } /** * Get formatted graphs. * * @return array */ protected function getFormattedGraphs() { if (!isset($this->formattedData['graphs'])) { $this->formattedData['graphs'] = $this->adapter->getGraphs(); } return $this->formattedData['graphs']; } /** * Get formatted images. * * @return array */ protected function getFormattedImages() { if (!isset($this->formattedData['images'])) { $this->formattedData['images'] = $this->adapter->getImages(); } return $this->formattedData['images']; } /** * Get formatted maps. * * @return array */ protected function getFormattedMaps() { if (!isset($this->formattedData['maps'])) { $this->formattedData['maps'] = $this->adapter->getMaps(); } return $this->formattedData['maps']; } /** * Get formatted screens. * * @return array */ protected function getFormattedScreens() { if (!isset($this->formattedData['screens'])) { $this->formattedData['screens'] = $this->adapter->getScreens(); } return $this->formattedData['screens']; } /** * Get formatted template screens. * * @return array */ protected function getFormattedTemplateDashboards() { if (!isset($this->formattedData['templateDashboards'])) { $this->formattedData['templateDashboards'] = $this->adapter->getTemplateDashboards(); } return $this->formattedData['templateDashboards']; } /** * Get formatted media types. * * @return array */ protected function getFormattedMediaTypes() { if (!isset($this->formattedData['mediaTypes'])) { $this->formattedData['mediaTypes'] = $this->adapter->getMediaTypes(); } return $this->formattedData['mediaTypes']; } /** * Get items keys order tree, to ensure that master item will be inserted or updated before any of it dependent * item. Returns associative array where key is item index and value is item dependency level. * * @param string $master_key_identifier String containing master key name used to identify item master. * * @return array */ protected function getItemsOrder($master_key_identifier) { $entities = $this->getFormattedItems(); return $this->getEntitiesOrder($master_key_identifier, $entities); } /** * Get discovery rules items prototypes keys order tree, to ensure that master item will be inserted or updated * before any of it dependent item. Returns associative array where key is item prototype index and value is item * prototype dependency level. * * @param string $master_key_identifier String containing master key name used to identify item master. * * @return array */ protected function getDiscoveryRulesItemsOrder($master_key_identifier) { $discovery_rules = $this->getFormattedDiscoveryRules(); $entities_order = []; foreach ($discovery_rules as $host_key => $items) { foreach ($items as $item) { if ($item['item_prototypes']) { $item_prototypes = [$host_key => $item['item_prototypes']]; $item_prototypes = $this->getEntitiesOrder($master_key_identifier, $item_prototypes, true); $entities_order[$host_key][$item['key_']] = $item_prototypes[$host_key]; } } } return $entities_order; } /** * Generic method to get entities order tree, to ensure that master entity will be inserted or updated before any * of it dependent entities. * Returns associative array where key is entity index in source array grouped by host key and value is entity * dependency level. * * @param string $master_key_identifier String containing master key name to identify item master. * @param array $host_entities Associative array of host key and host items. * @param bool $get_prototypes Option to get also master item prototypes not found in supplied input. * * @throws Exception if data is invalid. * * @return array */ protected function getEntitiesOrder($master_key_identifier, array $host_entities, $get_prototypes = false) { $find_keys = []; $find_hosts = []; $resolved_masters_cache = []; $hostkey_to_hostid = array_fill_keys(array_keys($host_entities), 0); foreach ($hostkey_to_hostid as $host_key => &$hostid) { $hostid = $this->referencer->resolveHostOrTemplate($host_key); } foreach ($host_entities as $host_key => $entities) { if (!array_key_exists($host_key, $hostkey_to_hostid)) { throw new Exception(_s('Incorrect value for field "%1$s": %2$s.', 'host', _s('value "%1$s" not found', $host_key) )); } if (!array_key_exists($host_key, $resolved_masters_cache)) { $resolved_masters_cache[$host_key] = []; } // Cache input array entities. foreach ($entities as $entity_key => $entity) { $resolved_masters_cache[$host_key][$entity['key_']] = [ 'type' => $entity['type'], $master_key_identifier => $entity[$master_key_identifier] ]; } // Search master entities not in input array. Will be requested from database. foreach ($entities as $entity_key => $entity) { if ($entity['type'] == ITEM_TYPE_DEPENDENT && array_key_exists('key', $entity[$master_key_identifier])) { $find_hosts[$hostkey_to_hostid[$host_key]] = true; $find_keys[$entity[$master_key_identifier]['key']] = true; } } } // There are entities to resolve from database, resolve and cache them recursively. if ($find_keys) { /* * For existing items, 'referencer' should be initialized before 'addItemRef' method will be used. * Registering reference when property 'itemRefs' is empty, will not allow first call of 'resolveValueMap' * method update references to existing items. */ $this->referencer->initItemsReferences(); $options = [ 'output' => ['key_', 'type', 'hostid', 'master_itemid'], 'hostids' => array_keys($find_hosts), 'filter' => ['key_' => array_keys($find_keys)], 'preservekeys' => true ]; $resolved_entities = API::Item()->get($options + ['webitems' => true]); if ($get_prototypes) { $resolved_entities += API::ItemPrototype()->get($options); } $resolve_entity_keys = []; $host_entity_idkey_hash = []; for ($level = 0; $level < ZBX_DEPENDENT_ITEM_MAX_LEVELS; $level++) { $find_ids = []; foreach ($resolved_entities as $entityid => $entity) { $host_key = array_search($entity['hostid'], $hostkey_to_hostid); $entity['key'] = $entity['key_']; unset($entity['key_']); $host_entity_idkey_hash[$host_key][$entityid] = $entity['key']; $this->referencer->addItemRef($entity['hostid'], $entity['key'], $entityid); $cache_entity = [ 'type' => $entity['type'] ]; if ($entity['type'] == ITEM_TYPE_DEPENDENT) { $master_itemid = $entity['master_itemid']; if (array_key_exists($master_itemid, $host_entity_idkey_hash[$host_key])) { $cache_entity[$master_key_identifier] = [ 'key' => $host_entity_idkey_hash[$host_key][$master_itemid] ]; } else { $find_ids[] = $entity['master_itemid']; $resolve_entity_keys[] = [ 'host' => $host_key, 'key' => $entity['key'], 'master_itemid' => $entity['master_itemid'] ]; } } $resolved_masters_cache[$host_key][$entity['key']] = $cache_entity; } if ($find_ids) { $options = [ 'output' => ['key_', 'type', 'hostid', 'master_itemid'], 'itemids' => $find_ids, 'preservekeys' => true ]; $resolved_entities = API::Item()->get($options + ['webitems' => true]); if ($get_prototypes) { $resolved_entities += API::ItemPrototype()->get($options); } } else { break; } } if ($find_ids) { throw new Exception(_s('Incorrect value for field "%1$s": %2$s.', 'master_itemid', _('maximum number of dependency levels reached') )); } foreach ($resolve_entity_keys as $entity) { $master_itemid = $entity['master_itemid']; if (!array_key_exists($entity['host'], $host_entity_idkey_hash) || !array_key_exists($master_itemid, $host_entity_idkey_hash[$entity['host']])) { throw new Exception(_s('Incorrect value for field "%1$s": %2$s.', 'master_itemid', _s('value "%1$s" not found', $master_itemid) )); } $master_key = $host_entity_idkey_hash[$entity['host']][$master_itemid]; $resolved_masters_cache[$entity['host']][$entity['key']] += [ $master_key_identifier => ['key' => $master_key] ]; } unset($resolve_entity_keys); unset($host_entity_idkey_hash); } // Resolve every entity dependency level. $tree = []; foreach ($host_entities as $host_key => $entities) { $hostid = $hostkey_to_hostid[$host_key]; $host_items_tree = []; foreach ($entities as $entity_index => $entity) { $level = 0; $traversal_path = [$entity['key_']]; while ($entity && $entity['type'] == ITEM_TYPE_DEPENDENT) { if (!array_key_exists('key', $entity[$master_key_identifier])) { throw new Exception(_s('Incorrect value for field "%1$s": %2$s.', 'master_itemid', _('cannot be empty') )); } $master_key = $entity[$master_key_identifier]['key']; if (array_key_exists($host_key, $resolved_masters_cache) && array_key_exists($master_key, $resolved_masters_cache[$host_key])) { $entity = $resolved_masters_cache[$host_key][$master_key]; if (in_array($master_key, $traversal_path) || ($entity['type'] == ITEM_TYPE_DEPENDENT && $entity[$master_key_identifier] && $master_key == $entity[$master_key_identifier]['key'])) { throw new Exception(_s('Incorrect value for field "%1$s": %2$s.', 'master_itemid', _('circular item dependency is not allowed') )); } $traversal_path[] = $master_key; $level++; } else { throw new Exception(_s('Incorrect value for field "%1$s": %2$s.', 'master_itemid', _s('value "%1$s" not found', $master_key) )); } if ($level > ZBX_DEPENDENT_ITEM_MAX_LEVELS) { throw new Exception(_s('Incorrect value for field "%1$s": %2$s.', 'master_itemid', _('maximum number of dependency levels reached') )); } } $host_items_tree[$entity_index] = $level; } $tree[$host_key] = $host_items_tree; } // Order item indexes in descending order by nesting level. foreach ($tree as $host_key => &$item_indexes) { asort($item_indexes); } unset($item_indexes); return $tree; } }
💾 保存文件
← 返回文件管理器