<?php /* ** Zabbix ** Copyright (C) 2001-2025 Zabbix SIA ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. **/ require_once 'vendor/autoload.php'; require_once dirname(__FILE__).'/../../../include/defines.inc.php'; require_once dirname(__FILE__).'/../../../include/hosts.inc.php'; require_once dirname(__FILE__).'/../../../include/db.inc.php'; class CDataHelper extends CAPIHelper { protected static $data = null; protected static $request = []; protected static $response = []; /** * Prepare request for API call and make API call (@see callRaw). * * @param string $method API method to be called. * @param mixed $params API call params. * * @return array * * @throws Exception on API error */ public static function call($method, $params) { global $URL; if (!$URL) { $URL = PHPUNIT_URL.'api_jsonrpc.php'; } static::$request = []; static::$response = []; if (CAPIHelper::getSessionId() === null) { CAPIHelper::createSessionId(); } $response = CAPIHelper::call($method, $params); if (array_key_exists('error', $response)) { throw new Exception('API call failed: '.json_encode($response['error'], JSON_PRETTY_PRINT)); } if (!array_key_exists('result', $response)) { throw new Exception('API call failed: result is not present'); } static::$request = (CTestArrayHelper::isAssociative($params)) ? [$params] : $params; static::$response = $response['result']; return static::$response; } /** * Prepare request for API call and make API call (@see callRaw). * * @param string $method API method to be called. * @param mixed $params API call params. * * @return array * * @throws Exception on API error */ public static function getIds($field) { $ids = []; $result = reset(static::$response); if (count(static::$request) !== count($result)) { throw new Exception('Failed to get ids: record counts don\'t match'); } foreach (static::$request as $i => $object) { if (!array_key_exists($field, $object)) { throw new Exception('Failed to get ids: field "'.$field.'" is not present in request.'); } if (!array_key_exists($i, $result)) { throw new Exception('Failed to get ids: element ('.$i.') is not present in result.'); } if (array_key_exists($object[$field], $ids)) { throw new Exception('Failed to get ids: field "'.$field.'" is not unique.'); } $ids[$object[$field]] = $result[$i]; } return $ids; } /** * Create host with items and discovery rules. * * @param mixed $params API call params. * In addition to the default host.create params, "items" and "discoveryrules" can be set * for any of the host in order to create host items and discovery rules. * * @return array */ public static function createHosts($params) { return static::createHostTemplate($params, 'host'); } /** * Create template with items and discovery rules. * * @param mixed $params API call params * * @return array */ public static function createTemplates($params) { return static::createHostTemplate($params, 'template'); } /** * Execute creation of host or template. * * @param mixed $params API call params * @param string $object host or template object * * @return array */ public static function createHostTemplate($params, $object) { $items = []; $discoveryrules = []; foreach ($params as &$param) { if (array_key_exists('items', $param)) { $items[$param['host']] = $param['items']; unset($param['items']); } if (array_key_exists('discoveryrules', $param)) { $discoveryrules[$param['host']] = $param['discoveryrules']; unset($param['discoveryrules']); } } unset($param); static::call($object.'.create', $params); $objectids = static::getIds('host'); $result = [ $object.'ids' => $objectids ]; if ($items) { $result['itemids'] = static::createItems('item', $items, $objectids, $object); } if ($discoveryrules) { $result['discoveryruleids'] = static::createItems('discoveryrule', $discoveryrules, $objectids, $object); } return $result; } /** * Get host interfaces. * * @param array $hostids host ids * * @return array */ public static function getInterfaces($hostids) { $hosts = static::call('host.get', [ 'output' => ['host'], 'hostids' => array_values($hostids), 'selectInterfaces' => ['interfaceid', 'useip', 'ip', 'type', 'dns', 'port', 'main'] ]); $result['default_interfaces'] = []; $result['ids'] = []; foreach ($hosts as $host) { foreach ($host['interfaces'] as $interface) { if ($interface['main'] == INTERFACE_PRIMARY) { $result['default_interfaces'][$host['host']][$interface['type']] = $interface['interfaceid']; } $address = ($interface['useip'] == 1) ? $interface['ip'] : $interface['dns']; $result['ids'][$host['host']][$address.':'.$interface['port']] = $interface['interfaceid']; } } return $result; } /** * Create items or discovery rule for host and template. * * @param string $type item or discoveryrule type * @param mixed $items API call items or discovery params * @param array $objectids host or template ids * @param string $object host or template * * @return array * * @throws Exception on API error */ public static function createItems($type, $items, $objectids, $object = 'host') { $request = []; foreach ($items as $host => $host_items) { foreach ($host_items as $item) { $item['hostid'] = $objectids[$host]; if ($object === 'host') { $interfaces = static::getInterfaces($objectids); if (array_key_exists($host, $interfaces['default_interfaces'])) { $interface_type = null; switch (CTestArrayHelper::get($item, 'type')) { case ITEM_TYPE_ZABBIX: case ITEM_TYPE_ZABBIX_ACTIVE: $interface_type = 1; break; case ITEM_TYPE_SNMP: case ITEM_TYPE_SNMPTRAP: $interface_type = 2; break; case ITEM_TYPE_IPMI: $interface_type = 3; break; case ITEM_TYPE_JMX: $interface_type = 4; break; } if ($interface_type !== null && array_key_exists($interface_type, $interfaces['default_interfaces'][$host])) { $item['interfaceid'] = $interfaces['default_interfaces'][$host][$interface_type]; } } if (array_key_exists($host, $interfaces['ids'])) { $interface = CTestArrayHelper::get($item, 'interface'); unset($item['interface']); if ($interface !== null && array_key_exists($$interfaces['ids'][$host], $interface)) { $item['interfaceid'] = $interfaces['ids'][$host][$interface]; } } } $request[] = $item; } } // Create items or discovery rules. $response = static::call($type.'.create', $request); $i = 0; $result = []; foreach ($items as $host => $host_items) { foreach ($host_items as $item) { if (!array_key_exists($i, $response['itemids'])) { throw new Exception('Failed to get ids: element ('.$i.') is not present in result.'); } $result[$host.':'.$item['key_']] = $response['itemids'][$i++]; } } return $result; } /** * Load the data source data from the file cache. */ protected static function preload() { if (static::$data === null) { static::$data = []; if (!defined('PHPUNIT_DATA_DIR')) { return; } foreach (new DirectoryIterator(PHPUNIT_DATA_DIR) as $file) { if ($file->isDot() || $file->isDir() || strtolower($file->getExtension()) !== 'json') { continue; } $name = $file->getBasename('.'.$file->getExtension()); static::$data[$name] = json_decode(file_get_contents($file->getPathname()), true); } } } /** * Get data from the data sources. * * @param mixed $path data path to look for * @param mixed $default default value to be returned if data doesn't exist * * @return mixed */ public static function get($path, $default = null) { return CTestArrayHelper::get(static::$data, $path, $default); } /** * Load specific data source data. * * @param mixed $source name of the data source(s) * * @return boolean * * @throws \Exception */ public static function load($source) { if (is_array($source)) { $result = true; foreach ($source as $name) { if (!static::load($name)) { $result = false; } } return $result; } static::preload(); if (array_key_exists($source, static::$data)) { return true; } try { $path = PHPUNIT_DATA_SOURCES_DIR.$source.'.php'; if (!file_exists($path)) { throw new \Exception('File "'.$path.'" doesn\'t exist.'); } require_once $path; static::$data[$source] = forward_static_call([$source, 'load']); if (defined('PHPUNIT_DATA_DIR')) { $data = json_encode(static::get($source)); file_put_contents(PHPUNIT_DATA_DIR.$source.'.json', $data); } } catch (\Exception $e) { echo 'Failed to load data from data source "'.$source.'".'."\n\n".$e->getMessage()."\n".$e->getTraceAsString(); return false; } return true; } /** * Add data to item. * * @param string $itemid item id * @param array $values value that should be sent to item * @param mixed $time time when value was received */ public static function addItemData($itemid, $values, $time = null) { if (!is_array($values)) { $values = [$values]; } if ($time === null) { if (is_array($values)) { $offset = time(); $time = []; for ($i = count($values); $i > 0; $i--) { $time[] = $offset - $i; } } else { $time = time(); } } elseif (is_array($time)) { if (count($time) !== count($values)) { throw new Exception('Value count should match the time record count.'); } $time = array_values($time); } // Set correct history table where to insert data. $suffix = static::getItemDataTableSuffix($itemid); foreach (array_values($values) as $key => $value) { $clock = is_array($time) ? $time[$key] : $time; // If value is an array, it means that we are dealing with trend data, which is inserted in differently. if (is_array($value)) { DBexecute('INSERT INTO trends'.$suffix.' (itemid, clock, num, value_min, value_avg,'. ' value_max) VALUES ('.zbx_dbstr($itemid).', '.zbx_dbstr($clock).', '.zbx_dbstr($value['num']). ', '.zbx_dbstr($value['min']).', '.zbx_dbstr($value['avg']).', '.zbx_dbstr($value['max']).')' ); } else { DBexecute('INSERT INTO history'.$suffix.' (itemid, clock, value) VALUES ('.zbx_dbstr($itemid). ', '.zbx_dbstr($clock).', '.zbx_dbstr($value).')' ); } } } /** * Remove item data from history and trends tables. * * @param string|array $itemids item id(s) */ public static function removeItemData($itemids) { $groups = []; if (!is_array($itemids)) { $itemids = [$itemids]; } foreach ($itemids as $itemid) { $groups[self::getItemDataTableSuffix($itemid)][] = zbx_dbstr($itemid); } foreach (array_keys($groups) as $suffix) { DBexecute('DELETE FROM history'.$suffix.' WHERE itemid IN ('.implode(',', $groups[$suffix]).')'); if ($suffix === '_uint' || $suffix === '') { DBexecute('DELETE FROM trends'.$suffix.' WHERE itemid IN ('.implode(',', $groups[$suffix]).')'); } } } /** * Get history data table. * * @param string $itemid item id */ public static function getItemDataTableSuffix($itemid) { // Check item value type to set correct history table. $value_type = CDBHelper::getValue('SELECT value_type FROM items where itemid='.zbx_dbstr($itemid)); $suffixes = ['', '_str', '_log', '_uint', '_text']; if (!array_key_exists($value_type, $suffixes)) { throw new Exception('Unsupported item value type: '.$value_type); } return $suffixes[$value_type]; } }