Пример #1
0
 /**
  * Format discovery rule.
  *
  * @param array $discoveryRule
  *
  * @return array
  */
 protected function formatDiscoveryRule(array $discoveryRule)
 {
     $discoveryRule = $this->renameItemFields($discoveryRule);
     if (!empty($discoveryRule['item_prototypes'])) {
         foreach ($discoveryRule['item_prototypes'] as &$prototype) {
             $prototype = $this->renameItemFields($prototype);
             CArrayHelper::convertFieldToArray($prototype, 'applications');
         }
         unset($prototype);
     } else {
         $discoveryRule['item_prototypes'] = array();
     }
     if (!empty($discoveryRule['trigger_prototypes'])) {
         foreach ($discoveryRule['trigger_prototypes'] as &$trigger) {
             $trigger['expression'] = $this->triggerExpressionConverter->convert($trigger['expression']);
             $trigger = $this->renameTriggerFields($trigger);
         }
         unset($trigger);
     } else {
         $discoveryRule['trigger_prototypes'] = array();
     }
     if (!empty($discoveryRule['graph_prototypes'])) {
         foreach ($discoveryRule['graph_prototypes'] as &$graph) {
             $graph = $this->renameGraphFields($graph);
         }
         unset($graph);
     } else {
         $discoveryRule['graph_prototypes'] = array();
     }
     if (!empty($discoveryRule['host_prototypes'])) {
         foreach ($discoveryRule['host_prototypes'] as &$hostPrototype) {
             CArrayHelper::convertFieldToArray($hostPrototype, 'group_prototypes');
             CArrayHelper::convertFieldToArray($hostPrototype, 'templates');
         }
         unset($hostPrototype);
     } else {
         $discoveryRule['host_prototypes'] = array();
     }
     if (!empty($discoveryRule['filter'])) {
         // array filter structure
         if (is_array($discoveryRule['filter'])) {
             CArrayHelper::convertFieldToArray($discoveryRule['filter'], 'conditions');
         } else {
             list($filterMacro, $filterValue) = explode(':', $discoveryRule['filter']);
             if ($filterMacro) {
                 $discoveryRule['filter'] = array('evaltype' => CONDITION_EVAL_TYPE_AND_OR, 'formula' => '', 'conditions' => array(array('macro' => $filterMacro, 'value' => $filterValue, 'operator' => CONDITION_OPERATOR_REGEXP)));
             } else {
                 unset($discoveryRule['filter']);
             }
         }
     }
     return $discoveryRule;
 }
Пример #2
0
 public static function parseMain($rules)
 {
     $triggerExpressionConverter = new C24TriggerConverter(new CFunctionMacroParser(), new CMacroParser('#'));
     $triggersForDependencies = array();
     if ($rules['hosts']['updateExisting'] || $rules['hosts']['createMissing'] || $rules['templates']['createMissing'] || $rules['templates']['updateExisting']) {
         $xpath = new DOMXPath(self::$xml);
         $hosts = $xpath->query('hosts/host');
         // stores parsed host and template IDs
         $processedHostIds = array();
         // stores converted trigger expressions for each host
         $triggerExpressions = array();
         // stores converted item keys for each host
         $itemKeys = array();
         // process hosts
         foreach ($hosts as $host) {
             $host_db = self::mapXML2arr($host, XML_TAG_HOST);
             if (!isset($host_db['status'])) {
                 $host_db['status'] = HOST_STATUS_TEMPLATE;
             }
             if ($host_db['status'] == HOST_STATUS_TEMPLATE) {
                 $current_host = API::Template()->get(array('output' => array('templateid'), 'filter' => array('host' => $host_db['host']), 'nopermissions' => true, 'limit' => 1));
             } else {
                 $current_host = API::Host()->get(array('output' => array('hostid'), 'filter' => array('host' => $host_db['host']), 'nopermissions' => true, 'limit' => 1));
             }
             if (!$current_host && ($host_db['status'] == HOST_STATUS_TEMPLATE && !$rules['templates']['createMissing'] || $host_db['status'] != HOST_STATUS_TEMPLATE && !$rules['hosts']['createMissing'])) {
                 continue;
             }
             if ($current_host && ($host_db['status'] == HOST_STATUS_TEMPLATE && !$rules['templates']['updateExisting'] || $host_db['status'] != HOST_STATUS_TEMPLATE && !$rules['hosts']['updateExisting'])) {
                 continue;
             }
             // there were no host visible names in 1.8
             if (!isset($host_db['name'])) {
                 $host_db['name'] = $host_db['host'];
             }
             // host will have no interfaces - we will be creating them separately
             $host_db['interfaces'] = null;
             // it is possible, that data is imported from 1.8, where there was only one network interface per host
             /**
              * @todo when new XML format will be introduced, this check should be changed to XML version check
              */
             $oldVersionInput = $host_db['status'] != HOST_STATUS_TEMPLATE;
             $interfaces = array();
             // rearranging host structure, so it would look more like 2.0 host
             if ($oldVersionInput) {
                 // the main interface is always "agent" type
                 if (!is_null($host_db['ip'])) {
                     $interfaces[] = array('main' => INTERFACE_PRIMARY, 'type' => INTERFACE_TYPE_AGENT, 'useip' => $host_db['useip'], 'ip' => $host_db['ip'], 'dns' => $host_db['dns'], 'port' => $host_db['port']);
                 }
                 // now we need to check if host had SNMP items. If it had, we need an SNMP interface for every different port.
                 $items = $xpath->query('items/item', $host);
                 $snmp_interface_ports_created = array();
                 foreach ($items as $item) {
                     $item_db = self::mapXML2arr($item, XML_TAG_ITEM);
                     if (($item_db['type'] == ITEM_TYPE_SNMPV1 || $item_db['type'] == ITEM_TYPE_SNMPV2C || $item_db['type'] == ITEM_TYPE_SNMPV3) && !isset($snmp_interface_ports_created[$item_db['snmp_port']])) {
                         $interfaces[] = array('main' => $snmp_interface_ports_created ? INTERFACE_SECONDARY : INTERFACE_PRIMARY, 'type' => INTERFACE_TYPE_SNMP, 'useip' => $host_db['useip'], 'ip' => $host_db['ip'], 'dns' => $host_db['dns'], 'port' => $item_db['snmp_port']);
                         $snmp_interface_ports_created[$item_db['snmp_port']] = 1;
                     }
                 }
                 unset($snmp_interface_ports_created);
                 // it was a temporary variable
                 // we need to add ipmi interface if at least one ipmi item exists
                 foreach ($items as $item) {
                     $item_db = self::mapXML2arr($item, XML_TAG_ITEM);
                     if ($item_db['type'] == ITEM_TYPE_IPMI) {
                         // when saving a host in 1.8, it's possible to set useipmi=1 and not to fill an IP address
                         // we were not really sure what to do with this host,
                         // and decided to take host IP address instead and show info message about this
                         if ($host_db['ipmi_ip'] === '') {
                             $ipmi_ip = $host_db['ip'];
                             info(_s('Host "%s" has "useipmi" parameter checked, but has no "ipmi_ip" parameter! Using host IP address as an address for IPMI interface.', $host_db['host']));
                         } else {
                             $ipmi_ip = $host_db['ipmi_ip'];
                         }
                         $interfaces[] = array('main' => INTERFACE_PRIMARY, 'type' => INTERFACE_TYPE_IPMI, 'useip' => INTERFACE_USE_IP, 'ip' => $ipmi_ip, 'dns' => '', 'port' => $host_db['ipmi_port']);
                         // we need only one ipmi interface
                         break;
                     }
                 }
             }
             if ($current_host) {
                 $options = array('filter' => array('host' => $host_db['host']), 'output' => API_OUTPUT_EXTEND, 'editable' => true, 'selectInterfaces' => API_OUTPUT_EXTEND);
                 if ($host_db['status'] == HOST_STATUS_TEMPLATE) {
                     $current_host = API::Template()->get($options);
                 } else {
                     $current_host = API::Host()->get($options);
                 }
                 if (empty($current_host)) {
                     throw new Exception(_s('No permission for host "%1$s".', $host_db['host']));
                 } else {
                     $current_host = reset($current_host);
                 }
                 // checking if host already exists - then some of the interfaces may not need to be created
                 if ($host_db['status'] != HOST_STATUS_TEMPLATE) {
                     $currentMainInterfaces = array();
                     $currentInterfacesByType = array();
                     // group existing main interfaces by interface type into $currentMainInterfaces
                     // and group interfaces by type into $currentInterfacesByType
                     foreach ($current_host['interfaces'] as $currentInterface) {
                         if ($currentInterface['main'] == INTERFACE_PRIMARY) {
                             $currentMainInterfaces[$currentInterface['type']] = $currentInterface;
                         }
                         $currentInterfacesByType[$currentInterface['type']][] = $currentInterface;
                     }
                     // loop through all interfaces we got from XML
                     foreach ($interfaces as &$interfaceXml) {
                         $interfaceXmlType = $interfaceXml['type'];
                         // if this is the primary interface of some type and we have default interface of same type
                         // in current (target) host, re-use "interfaceid" of the matching default interface
                         // in current host
                         if ($interfaceXml['main'] == INTERFACE_PRIMARY && isset($currentMainInterfaces[$interfaceXmlType])) {
                             $interfaceXml['interfaceid'] = $currentMainInterfaces[$interfaceXmlType]['interfaceid'];
                         } else {
                             // otherwise, loop through all current (target) host interfaces with type of current
                             // imported interface and re-use "interfaceid" in case if all interface parameters match
                             if (isset($currentInterfacesByType[$interfaceXmlType])) {
                                 foreach ($currentInterfacesByType[$interfaceXmlType] as $currentInterface) {
                                     if ($currentInterface['ip'] == $interfaceXml['ip'] && $currentInterface['dns'] == $interfaceXml['dns'] && $currentInterface['port'] == $interfaceXml['port'] && $currentInterface['useip'] == $interfaceXml['useip']) {
                                         $interfaceXml['interfaceid'] = $currentInterface['interfaceid'];
                                         break;
                                     }
                                 }
                             }
                         }
                     }
                     unset($interfaceXml);
                     $host_db['interfaces'] = $interfaces;
                 }
             } elseif ($host_db['status'] != HOST_STATUS_TEMPLATE) {
                 $host_db['interfaces'] = $interfaces;
             }
             // HOST GROUPS {{{
             $groups = $xpath->query('groups/group', $host);
             $host_db['groups'] = array();
             $groups_to_parse = array();
             foreach ($groups as $group) {
                 $groups_to_parse[] = array('name' => $group->nodeValue);
             }
             if (empty($groups_to_parse)) {
                 $groups_to_parse[] = array('name' => ZBX_DEFAULT_IMPORT_HOST_GROUP);
             }
             foreach ($groups_to_parse as $group) {
                 $hostGroup = API::HostGroup()->get(array('output' => API_OUTPUT_EXTEND, 'filter' => $group, 'editable' => true, 'limit' => 1));
                 if ($hostGroup) {
                     $host_db['groups'][] = reset($hostGroup);
                 } else {
                     if ($rules['groups']['createMissing']) {
                         $result = API::HostGroup()->create($group);
                         if ($result) {
                             $newHostGroup = API::HostGroup()->get(array('output' => API_OUTPUT_EXTEND, 'groupids' => $result['groupids'], 'limit' => 1));
                             $host_db['groups'][] = reset($newHostGroup);
                         }
                     } else {
                         throw new Exception(_s('No permissions for host group "%1$s".', $group['name']));
                     }
                 }
             }
             // }}} HOST GROUPS
             // MACROS
             $macros = $xpath->query('macros/macro', $host);
             if ($macros->length > 0) {
                 $host_db['macros'] = array();
                 foreach ($macros as $macro) {
                     $host_db['macros'][] = self::mapXML2arr($macro, XML_TAG_MACRO);
                 }
             }
             // }}} MACROS
             // host inventory
             if ($oldVersionInput) {
                 if (!isset($host_db['inventory'])) {
                     $host_db['inventory'] = array();
                 }
                 $inventoryNode = $xpath->query('host_profile/*', $host);
                 if ($inventoryNode->length > 0) {
                     foreach ($inventoryNode as $field) {
                         $newInventoryName = self::mapInventoryName($field->nodeName);
                         $host_db['inventory'][$newInventoryName] = $field->nodeValue;
                     }
                 }
                 $inventoryNodeExt = $xpath->query('host_profiles_ext/*', $host);
                 if ($inventoryNodeExt->length > 0) {
                     foreach ($inventoryNodeExt as $field) {
                         $newInventoryName = self::mapInventoryName($field->nodeName);
                         if (isset($host_db['inventory'][$newInventoryName]) && $field->nodeValue !== '') {
                             $host_db['inventory'][$newInventoryName] .= "\r\n\r\n";
                             $host_db['inventory'][$newInventoryName] .= $field->nodeValue;
                         } else {
                             $host_db['inventory'][$newInventoryName] = $field->nodeValue;
                         }
                     }
                 }
                 $host_db['inventory_mode'] = isset($host_db['inventory']) ? HOST_INVENTORY_MANUAL : HOST_INVENTORY_DISABLED;
             }
             if (isset($host_db['proxy_hostid'])) {
                 $proxy_exists = API::Proxy()->get(array('output' => array('proxyid'), 'proxyids' => $host_db['proxy_hostid']));
                 if (empty($proxy_exists)) {
                     $host_db['proxy_hostid'] = 0;
                 }
             }
             if ($current_host && ($rules['hosts']['updateExisting'] || $rules['templates']['updateExisting'])) {
                 if ($host_db['status'] == HOST_STATUS_TEMPLATE) {
                     $host_db['templateid'] = $current_host['templateid'];
                     $result = API::Template()->update($host_db);
                     $current_hostid = $current_host['templateid'];
                 } else {
                     $host_db['hostid'] = $current_host['hostid'];
                     $result = API::Host()->update($host_db);
                     $current_hostid = $current_host['hostid'];
                 }
             }
             if (!$current_host && ($rules['hosts']['createMissing'] || $rules['templates']['createMissing'])) {
                 if ($host_db['status'] == HOST_STATUS_TEMPLATE) {
                     $result = API::Template()->create($host_db);
                     $current_hostid = reset($result['templateids']);
                 } else {
                     $result = API::Host()->create($host_db);
                     $current_hostid = reset($result['hostids']);
                 }
             }
             // store parsed host IDs
             $processedHostIds[$host_db['host']] = $current_hostid;
         }
         // gather triggers and convert old expressions
         $triggersXML = array();
         // cycle each host and gather trigger descriptions and expressions
         foreach ($hosts as $host) {
             $host_db = self::mapXML2arr($host, XML_TAG_HOST);
             $current_hostid = isset($processedHostIds[$host_db['host']]) ? $processedHostIds[$host_db['host']] : false;
             if ($current_hostid) {
                 $triggersXML[$current_hostid] = array();
                 $triggerExpressions[$host_db['host']] = array();
                 $oldVersionInput = $host_db['status'] != HOST_STATUS_TEMPLATE;
                 $triggers = $xpath->query('triggers/trigger', $host);
                 foreach ($triggers as $trigger) {
                     $trigger_db = self::mapXML2arr($trigger, XML_TAG_TRIGGER);
                     $oldExpression = $trigger_db['expression'];
                     if (!isset($triggerExpressions[$host_db['host']][$trigger_db['description']])) {
                         $triggerExpressions[$host_db['host']][$trigger_db['description']] = array();
                     }
                     if ($oldVersionInput) {
                         $expressionPart = explode(':', $trigger_db['expression']);
                         $keyName = explode(',', $expressionPart[1], 2);
                         if (count($keyName) == 2) {
                             $keyValue = explode('.', $keyName[1], 2);
                             $key = $keyName[0] . "," . $keyValue[0];
                             if (in_array($keyName[0], self::$oldKeys) || in_array($keyName[0], self::$oldKeysPref)) {
                                 $trigger_db['expression'] = str_replace($key, self::convertOldSimpleKey($key), $trigger_db['expression']);
                             }
                         }
                     }
                     // {HOSTNAME} is here for backward compatibility
                     $trigger_db['expression'] = str_replace('{{HOSTNAME}:', '{' . $host_db['host'] . ':', $trigger_db['expression']);
                     $trigger_db['expression'] = str_replace('{{HOST.HOST}:', '{' . $host_db['host'] . ':', $trigger_db['expression']);
                     $trigger_db['expression'] = $triggerExpressionConverter->convert($trigger_db['expression']);
                     $triggersXML[$current_hostid][$trigger_db['description']][$trigger_db['expression']] = $trigger_db['expression'];
                     $triggerExpressions[$host_db['host']][$trigger_db['description']][$oldExpression] = $trigger_db['expression'];
                 }
             }
         }
         // delete missing triggers
         if ($rules['triggers']['deleteMissing']) {
             // select triggers from parsed hosts
             $dbTriggers = API::Trigger()->get(array('output' => array('triggerid', 'description', 'expression'), 'expandExpression' => true, 'hostids' => $processedHostIds, 'selectHosts' => array('hostid'), 'preservekeys' => true, 'nopermissions' => true, 'inherited' => false, 'filter' => array('flags' => ZBX_FLAG_DISCOVERY_NORMAL)));
             // find corresponding trigger ID by description and expression
             $triggerIdsXML = array();
             foreach ($dbTriggers as $dbTrigger) {
                 $hostId = reset($dbTrigger['hosts']);
                 if (isset($triggersXML[$hostId['hostid']][$dbTrigger['description']][$dbTrigger['expression']])) {
                     $triggerIdsXML[$dbTrigger['triggerid']] = $dbTrigger['triggerid'];
                 }
             }
             $triggersToDelete = array_diff_key($dbTriggers, $triggerIdsXML);
             $triggerIdsToDelete = array();
             // 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
             foreach ($triggersToDelete as $triggerId => $trigger) {
                 $triggerHostIds = array_flip(zbx_objectValues($trigger['hosts'], 'hostid'));
                 if (!array_diff_key($triggerHostIds, array_flip($processedHostIds))) {
                     $triggerIdsToDelete[] = $triggerId;
                 }
             }
             if ($triggerIdsToDelete) {
                 API::Trigger()->delete($triggerIdsToDelete);
             }
         }
         // delete missing graphs
         if ($rules['graphs']['deleteMissing']) {
             $graphsXML = array();
             // cycle each host and gather all graph names
             foreach ($hosts as $host) {
                 $host_db = self::mapXML2arr($host, XML_TAG_HOST);
                 $current_hostid = isset($processedHostIds[$host_db['host']]) ? $processedHostIds[$host_db['host']] : false;
                 if ($current_hostid) {
                     $graphsXML[$current_hostid] = array();
                     $graphs = $xpath->query('graphs/graph', $host);
                     foreach ($graphs as $graph) {
                         $graph_db = self::mapXML2arr($graph, XML_TAG_GRAPH);
                         $graphsXML[$current_hostid][$graph_db['name']] = $graph_db['name'];
                     }
                 }
             }
             // select graphs from already parsed hosts
             $dbGraphs = API::Graph()->get(array('output' => array('graphid', 'name'), 'hostids' => $processedHostIds, 'selectHosts' => array('hostid'), 'preservekeys' => true, 'nopermissions' => true, 'inherited' => false, 'filter' => array('flags' => ZBX_FLAG_DISCOVERY_NORMAL)));
             $graphIdsXML = array();
             foreach ($dbGraphs as $dbGraph) {
                 $hostId = reset($dbGraph['hosts']);
                 if (isset($graphsXML[$hostId['hostid']][$dbGraph['name']])) {
                     $graphIdsXML[$dbGraph['graphid']] = $dbGraph['graphid'];
                 }
             }
             $graphsToDelete = array_diff_key($dbGraphs, $graphIdsXML);
             $graphsIdsToDelete = array();
             // 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
             foreach ($graphsToDelete as $graphId => $graph) {
                 $graphHostIds = array_flip(zbx_objectValues($graph['hosts'], 'hostid'));
                 if (!array_diff_key($graphHostIds, array_flip($processedHostIds))) {
                     $graphsIdsToDelete[] = $graphId;
                 }
             }
             if ($graphsIdsToDelete) {
                 API::Graph()->delete($graphsIdsToDelete);
             }
         }
         // gather items and convert old keys
         $itemsXML = array();
         foreach ($hosts as $host) {
             $host_db = self::mapXML2arr($host, XML_TAG_HOST);
             $current_hostid = isset($processedHostIds[$host_db['host']]) ? $processedHostIds[$host_db['host']] : false;
             if ($current_hostid) {
                 $itemsXML[$current_hostid] = array();
                 $itemKeys[$host_db['host']] = array();
                 $oldVersionInput = $host_db['status'] != HOST_STATUS_TEMPLATE;
                 $items = $xpath->query('items/item', $host);
                 foreach ($items as $item) {
                     $item_db = self::mapXML2arr($item, XML_TAG_ITEM);
                     if ($oldVersionInput) {
                         $oldKey = $item_db['key_'];
                         $item_db['key_'] = self::convertOldSimpleKey($item_db['key_']);
                         $itemKeys[$host_db['host']][$oldKey] = $item_db['key_'];
                     }
                     $itemsXML[$current_hostid][$item_db['key_']] = $item_db['key_'];
                 }
             }
         }
         // delete missing items
         if ($rules['items']['deleteMissing']) {
             $dbItems = API::Item()->get(array('output' => array('itemid', 'key_', 'hostid'), 'hostids' => $processedHostIds, 'preservekeys' => true, 'nopermissions' => true, 'inherited' => false, 'filter' => array('flags' => ZBX_FLAG_DISCOVERY_NORMAL)));
             $itemIdsXML = array();
             foreach ($dbItems as $dbItem) {
                 if (isset($itemsXML[$dbItem['hostid']][$dbItem['key_']])) {
                     $itemIdsXML[$dbItem['itemid']] = $dbItem['itemid'];
                 }
             }
             $itemsToDelete = array_diff_key($dbItems, $itemIdsXML);
             if ($itemsToDelete) {
                 API::Item()->delete(array_keys($itemsToDelete));
             }
         }
         // delete missing applications
         if ($rules['applications']['deleteMissing']) {
             $applicationsXML = array();
             foreach ($hosts as $host) {
                 $host_db = self::mapXML2arr($host, XML_TAG_HOST);
                 $current_hostid = isset($processedHostIds[$host_db['host']]) ? $processedHostIds[$host_db['host']] : false;
                 if ($current_hostid) {
                     $items = $xpath->query('items/item', $host);
                     foreach ($items as $item) {
                         $applications = $xpath->query('applications/application', $item);
                         foreach ($applications as $application) {
                             $applicationsXML[$current_hostid][$application->nodeValue] = $application->nodeValue;
                         }
                     }
                 }
             }
             $dbApplications = API::Application()->get(array('output' => array('applicationid', 'hostid', 'name'), 'hostids' => $processedHostIds, 'preservekeys' => true, 'nopermissions' => true, 'inherited' => false));
             $applicationsIdsXML = array();
             foreach ($dbApplications as $dbApplication) {
                 if (isset($applicationsXML[$dbApplication['hostid']][$dbApplication['name']])) {
                     $applicationsIdsXML[$dbApplication['applicationid']] = $dbApplication['applicationid'];
                 }
             }
             $applicationsToDelete = array_diff_key($dbApplications, $applicationsIdsXML);
             if ($applicationsToDelete) {
                 API::Application()->delete(array_keys($applicationsToDelete));
             }
         }
         // cycle each host again and create/update other objects
         foreach ($hosts as $host) {
             $host_db = self::mapXML2arr($host, XML_TAG_HOST);
             if (!isset($host_db['status'])) {
                 $host_db['status'] = HOST_STATUS_TEMPLATE;
             }
             $current_hostid = isset($processedHostIds[$host_db['host']]) ? $processedHostIds[$host_db['host']] : false;
             if (!$current_hostid) {
                 continue;
             }
             $oldVersionInput = $host_db['status'] != HOST_STATUS_TEMPLATE;
             // TEMPLATES {{{
             if (!empty($rules['templateLinkage']['createMissing'])) {
                 $templates = $xpath->query('templates/template', $host);
                 $templateLinkage = array();
                 foreach ($templates as $template) {
                     $options = array('filter' => array('host' => $template->nodeValue), 'output' => array('templateid'), 'editable' => true);
                     $current_template = API::Template()->get($options);
                     if (empty($current_template)) {
                         throw new Exception(_s('No permission for template "%1$s".', $template->nodeValue));
                     }
                     $current_template = reset($current_template);
                     $templateLinkage[] = $current_template;
                 }
                 if ($templateLinkage) {
                     $result = API::Template()->massAdd(array('hosts' => array('hostid' => $current_hostid), 'templates' => $templateLinkage));
                     if (!$result) {
                         throw new Exception();
                     }
                 }
             }
             // }}} TEMPLATES
             // ITEMS {{{
             if ($rules['items']['updateExisting'] || $rules['items']['createMissing'] || $rules['applications']['createMissing']) {
                 // applications are located under items in version 1.8,
                 // so we need to get item list in any of these cases
                 $items = $xpath->query('items/item', $host);
                 if ($oldVersionInput) {
                     $interfaces = API::HostInterface()->get(array('hostids' => $current_hostid, 'output' => API_OUTPUT_EXTEND));
                     // we must know interface ids to assign them to items
                     $agent_interface_id = null;
                     $ipmi_interface_id = null;
                     $snmp_interfaces = array();
                     // hash 'port' => 'interfaceid'
                     foreach ($interfaces as $interface) {
                         switch ($interface['type']) {
                             case INTERFACE_TYPE_AGENT:
                                 $agent_interface_id = $interface['interfaceid'];
                                 break;
                             case INTERFACE_TYPE_IPMI:
                                 $ipmi_interface_id = $interface['interfaceid'];
                                 break;
                             case INTERFACE_TYPE_SNMP:
                                 $snmp_interfaces[$interface['port']] = $interface['interfaceid'];
                                 break;
                         }
                     }
                 }
                 // if this is an export from 1.8, we need to make some adjustments to items
                 // cycle each XML item
                 foreach ($items as $item) {
                     if ($rules['items']['updateExisting'] || $rules['items']['createMissing']) {
                         $item_db = self::mapXML2arr($item, XML_TAG_ITEM);
                         $item_db['hostid'] = $current_hostid;
                         // item needs interfaces
                         if ($oldVersionInput) {
                             // 'snmp_port' column was renamed to 'port'
                             if ($item_db['snmp_port'] != 0) {
                                 // zabbix agent items have no ports
                                 $item_db['port'] = $item_db['snmp_port'];
                             }
                             unset($item_db['snmp_port']);
                             // assigning appropriate interface depending on item type
                             switch ($item_db['type']) {
                                 // zabbix agent interface
                                 case ITEM_TYPE_ZABBIX:
                                 case ITEM_TYPE_SIMPLE:
                                 case ITEM_TYPE_EXTERNAL:
                                 case ITEM_TYPE_SSH:
                                 case ITEM_TYPE_TELNET:
                                     $item_db['interfaceid'] = $agent_interface_id;
                                     break;
                                     // snmp interface
                                 // snmp interface
                                 case ITEM_TYPE_SNMPV1:
                                 case ITEM_TYPE_SNMPV2C:
                                 case ITEM_TYPE_SNMPV3:
                                     // for an item with different port - different interface
                                     $item_db['interfaceid'] = $snmp_interfaces[$item_db['port']];
                                     break;
                                 case ITEM_TYPE_IPMI:
                                     $item_db['interfaceid'] = $ipmi_interface_id;
                                     break;
                                     // no interfaces required for these item types
                                 // no interfaces required for these item types
                                 case ITEM_TYPE_HTTPTEST:
                                 case ITEM_TYPE_CALCULATED:
                                 case ITEM_TYPE_AGGREGATE:
                                 case ITEM_TYPE_INTERNAL:
                                 case ITEM_TYPE_ZABBIX_ACTIVE:
                                 case ITEM_TYPE_TRAPPER:
                                 case ITEM_TYPE_DB_MONITOR:
                                     $item_db['interfaceid'] = null;
                                     break;
                             }
                             $item_db['key_'] = $itemKeys[$host_db['host']][$item_db['key_']];
                         }
                         $current_item = API::Item()->get(array('filter' => array('hostid' => $item_db['hostid'], 'key_' => $item_db['key_']), 'webitems' => true, 'editable' => true, 'output' => array('itemid')));
                         $current_item = reset($current_item);
                     }
                     // create applications independently of create or update item options
                     // in case we update items, we need to assign items to applications,
                     // so we also gather application IDs independetly of selected application options
                     $applications = $xpath->query('applications/application', $item);
                     $itemApplications = array();
                     $applicationsToAdd = array();
                     $applicationsIds = array();
                     foreach ($applications as $application) {
                         $application_db = array('name' => $application->nodeValue, 'hostid' => $current_hostid);
                         $current_application = API::Application()->get(array('filter' => $application_db, 'output' => API_OUTPUT_EXTEND));
                         $applicationValue = reset($current_application);
                         if ($current_application) {
                             if (!$itemApplications) {
                                 $itemApplications = $current_application;
                             } elseif (!in_array($applicationValue['applicationid'], $applicationsIds)) {
                                 $itemApplications = array_merge($itemApplications, $current_application);
                             }
                             $applicationsIds[] = $applicationValue['applicationid'];
                         } else {
                             $applicationsToAdd[] = $application_db;
                         }
                     }
                     if ($applicationsToAdd && $rules['applications']['createMissing']) {
                         $result = API::Application()->create($applicationsToAdd);
                         $newApplications = API::Application()->get(array('applicationids' => $result['applicationids'], 'output' => API_OUTPUT_EXTEND));
                         $itemApplications = array_merge($itemApplications, $newApplications);
                     }
                     if ($rules['items']['updateExisting'] || $rules['items']['createMissing']) {
                         // if item does not exist and there is no need to create it, skip item creation
                         if (!$current_item && !$rules['items']['createMissing']) {
                             info(_s('Item "%1$s" skipped - user rule.', $item_db['key_']));
                             continue;
                         }
                         // if item exists, but there there is no need for update, skip item update
                         if ($current_item && !$rules['items']['updateExisting']) {
                             info(_s('Item "%1$s" skipped - user rule.', $item_db['key_']));
                             continue;
                         }
                         if ($current_item && $rules['items']['updateExisting']) {
                             $item_db['itemid'] = $current_item['itemid'];
                             $result = API::Item()->update($item_db);
                             $current_item = API::Item()->get(array('itemids' => $result['itemids'], 'webitems' => true, 'output' => array('itemid')));
                         }
                         if (!$current_item && $rules['items']['createMissing']) {
                             $result = API::Item()->create($item_db);
                             $current_item = API::Item()->get(array('itemids' => $result['itemids'], 'webitems' => true, 'output' => array('itemid')));
                         }
                         // after items are created or updated, see to if items need to assigned to applications
                         if (isset($itemApplications) && $itemApplications) {
                             API::Application()->massAdd(array('applications' => $itemApplications, 'items' => $current_item));
                         }
                     }
                 }
             }
             // }}} ITEMS
             // TRIGGERS {{{
             if ($rules['triggers']['updateExisting'] || $rules['triggers']['createMissing']) {
                 $triggers = $xpath->query('triggers/trigger', $host);
                 $triggersToCreate = array();
                 $triggersToUpdate = array();
                 foreach ($triggers as $trigger) {
                     $trigger_db = self::mapXML2arr($trigger, XML_TAG_TRIGGER);
                     $trigger_db['expression'] = $triggerExpressions[$host_db['host']][$trigger_db['description']][$trigger_db['expression']];
                     $trigger_db['hostid'] = $current_hostid;
                     $currentTrigger = API::Trigger()->get(array('output' => array('triggerid'), 'filter' => array('description' => $trigger_db['description']), 'hostids' => array($current_hostid), 'selectHosts' => array('hostid'), 'nopermissions' => true, 'limit' => 1));
                     $currentTrigger = reset($currentTrigger);
                     if ($currentTrigger) {
                         $dbTriggers = API::Trigger()->get(array('output' => API_OUTPUT_EXTEND, 'filter' => array('description' => $trigger_db['description']), 'hostids' => array($current_hostid), 'editable' => true));
                         foreach ($dbTriggers as $dbTrigger) {
                             $expression = explode_exp($dbTrigger['expression']);
                             if (strcmp($trigger_db['expression'], $expression) == 0) {
                                 $currentTrigger = $dbTrigger;
                                 break;
                             }
                             if (!$currentTrigger) {
                                 throw new Exception(_s('No permission for trigger "%1$s".', $trigger_db['description']));
                             }
                         }
                     }
                     unset($trigger_db['hostid']);
                     if (!$currentTrigger && !$rules['triggers']['createMissing']) {
                         info(_s('Trigger "%1$s" skipped - user rule.', $trigger_db['description']));
                         continue;
                     }
                     if ($currentTrigger && !$rules['triggers']['updateExisting']) {
                         info(_s('Trigger "%1$s" skipped - user rule.', $trigger_db['description']));
                         continue;
                     }
                     if (!$currentTrigger && $rules['triggers']['createMissing']) {
                         $triggersToCreate[] = $trigger_db;
                     }
                     if ($currentTrigger && $rules['triggers']['updateExisting']) {
                         $trigger_db['triggerid'] = $currentTrigger['triggerid'];
                         $triggersToUpdate[] = $trigger_db;
                     }
                 }
                 if ($triggersToUpdate) {
                     $result = API::Trigger()->update($triggersToUpdate);
                     $triggersUpdated = API::Trigger()->get(array('output' => API_OUTPUT_EXTEND, 'triggerids' => $result['triggerids']));
                     $triggersForDependencies = array_merge($triggersForDependencies, $triggersUpdated);
                 }
                 if ($triggersToCreate) {
                     $result = API::Trigger()->create($triggersToCreate);
                     $triggersCreated = API::Trigger()->get(array('output' => API_OUTPUT_EXTEND, 'triggerids' => $result['triggerids']));
                     $triggersForDependencies = array_merge($triggersForDependencies, $triggersCreated);
                 }
             }
             // }}} TRIGGERS
             // GRAPHS {{{
             if ($rules['graphs']['updateExisting'] || $rules['graphs']['createMissing']) {
                 $graphs = $xpath->query('graphs/graph', $host);
                 $graphs_to_add = array();
                 $graphs_to_upd = array();
                 foreach ($graphs as $graph) {
                     // GRAPH ITEMS {{{
                     $gitems = $xpath->query('graph_elements/graph_element', $graph);
                     $graph_hostids = array();
                     $graph_items = array();
                     foreach ($gitems as $gitem) {
                         $gitem_db = self::mapXML2arr($gitem, XML_TAG_GRAPH_ELEMENT);
                         $data = explode(':', $gitem_db['host_key_']);
                         $gitem_host = array_shift($data);
                         // {HOSTNAME} is here for backward compatibility
                         $gitem_db['host'] = $gitem_host == '{HOSTNAME}' ? $host_db['host'] : $gitem_host;
                         $gitem_db['host'] = $gitem_host == '{HOST.HOST}' ? $host_db['host'] : $gitem_host;
                         if ($oldVersionInput) {
                             $data[0] = self::convertOldSimpleKey($data[0]);
                         }
                         $gitem_db['key_'] = implode(':', $data);
                         $itemExists = API::Item()->get(array('output' => array('itemid'), 'filter' => array('key_' => $gitem_db['key_']), 'webitems' => true, 'nopermissions' => true, 'limit' => 1));
                         if ($itemExists) {
                             $current_item = API::Item()->get(array('filter' => array('key_' => $gitem_db['key_']), 'webitems' => true, 'editable' => true, 'host' => $gitem_db['host'], 'output' => array('itemid', 'hostid')));
                             if (empty($current_item)) {
                                 throw new Exception(_s('No permission for item "%1$s".', $gitem_db['key_']));
                             }
                             $current_item = reset($current_item);
                             $graph_hostids[] = $current_item['hostid'];
                             $gitem_db['itemid'] = $current_item['itemid'];
                             $graph_items[] = $gitem_db;
                         } else {
                             throw new Exception(_s('Item "%1$s" does not exist.', $gitem_db['host_key_']));
                         }
                     }
                     // }}} GRAPH ITEMS
                     $graph_db = self::mapXML2arr($graph, XML_TAG_GRAPH);
                     $graph_db['hostids'] = $graph_hostids;
                     // do we need to show the graph legend, after it is imported?
                     // in 1.8, this setting was present only for pie and exploded graphs
                     // for other graph types we are always showing the legend
                     if ($graph_db['graphtype'] != GRAPH_TYPE_PIE && $graph_db['graphtype'] != GRAPH_TYPE_EXPLODED) {
                         $graph_db['show_legend'] = 1;
                     }
                     $current_graph = API::Graph()->get(array('output' => array('graphid'), 'selectHosts' => array('hostid', 'host'), 'hostids' => $graph_db['hostids'], 'filter' => array('name' => $graph_db['name']), 'nopermissions' => true, 'limit' => 1));
                     if ($current_graph) {
                         $current_graph = API::Graph()->get(array('output' => API_OUTPUT_EXTEND, 'hostids' => $graph_db['hostids'], 'filter' => array('name' => $graph_db['name']), 'editable' => true));
                         if (empty($current_graph)) {
                             throw new Exception(_s('No permission for graph "%1$s".', $graph_db['name']));
                         }
                         $current_graph = reset($current_graph);
                     }
                     if (!$current_graph && empty($rules['graphs']['createMissing'])) {
                         info(_s('Graph "%1$s" skipped - user rule.', $graph_db['name']));
                         continue;
                         // break if not update updateExisting
                     }
                     if ($current_graph && empty($rules['graphs']['updateExisting'])) {
                         info(_s('Graph "%1$s" skipped - user rule.', $graph_db['name']));
                         continue;
                         // break if not update updateExisting
                     }
                     if (!isset($graph_db['ymin_type'])) {
                         throw new Exception(_s('No "ymin_type" field for graph "%s".', $graph_db['name']));
                     }
                     if (!isset($graph_db['ymax_type'])) {
                         throw new Exception(_s('No "ymax_type" field for graph "%s".', $graph_db['name']));
                     }
                     if ($graph_db['ymin_type'] == GRAPH_YAXIS_TYPE_ITEM_VALUE) {
                         $item_data = explode(':', $graph_db['ymin_item_key'], 2);
                         if (count($item_data) < 2) {
                             throw new Exception(_s('Incorrect y min item for graph "%1$s".', $graph_db['name']));
                         }
                         if (!($item = get_item_by_key($item_data[1], $item_data[0]))) {
                             throw new Exception(_s('Missing item "%1$s" for host "%2$s".', $graph_db['ymin_item_key'], $host_db['host']));
                         }
                         $graph_db['ymin_itemid'] = $item['itemid'];
                     }
                     if ($graph_db['ymax_type'] == GRAPH_YAXIS_TYPE_ITEM_VALUE) {
                         $item_data = explode(':', $graph_db['ymax_item_key'], 2);
                         if (count($item_data) < 2) {
                             throw new Exception(_s('Incorrect y max item for graph "%1$s".', $graph_db['name']));
                         }
                         if (!($item = get_item_by_key($item_data[1], $item_data[0]))) {
                             throw new Exception(_s('Missing item "%1$s" for host "%2$s".', $graph_db['ymax_item_key'], $host_db['host']));
                         }
                         $graph_db['ymax_itemid'] = $item['itemid'];
                     }
                     $graph_db['gitems'] = $graph_items;
                     if ($current_graph) {
                         $graph_db['graphid'] = $current_graph['graphid'];
                         $graphs_to_upd[] = $graph_db;
                     } else {
                         $graphs_to_add[] = $graph_db;
                     }
                 }
                 if (!empty($graphs_to_add)) {
                     API::Graph()->create($graphs_to_add);
                 }
                 if (!empty($graphs_to_upd)) {
                     API::Graph()->update($graphs_to_upd);
                 }
             }
         }
         // DEPENDENCIES
         $dependencies = $xpath->query('dependencies/dependency');
         if ($dependencies->length > 0) {
             $triggersForDependencies = zbx_objectValues($triggersForDependencies, 'triggerid');
             $triggersForDependencies = array_flip($triggersForDependencies);
             $triggerDependencies = array();
             foreach ($dependencies as $dependency) {
                 $triggerDescription = $dependency->getAttribute('description');
                 $currentTrigger = get_trigger_by_description($triggerDescription);
                 if ($currentTrigger && isset($triggersForDependencies[$currentTrigger['triggerid']])) {
                     $dependsOnList = $xpath->query('depends', $dependency);
                     foreach ($dependsOnList as $dependsOn) {
                         $depTrigger = get_trigger_by_description($dependsOn->nodeValue);
                         if ($depTrigger) {
                             if (!isset($triggerDependencies[$currentTrigger['triggerid']])) {
                                 $triggerDependencies[$currentTrigger['triggerid']] = array('triggerid' => $currentTrigger['triggerid'], 'dependencies' => array());
                             }
                             $triggerDependencies[$currentTrigger['triggerid']]['dependencies'][] = array('triggerid' => $depTrigger['triggerid']);
                         }
                     }
                 }
             }
             if ($triggerDependencies) {
                 API::Trigger()->update($triggerDependencies);
             }
         }
     }
 }