/** * Convert item key * * @param string $value item key * * @return string converted item key */ public function convert($value) { if ($this->item_key_parser->parse($value) != CParser::PARSE_SUCCESS) { return $value; } if ($this->item_key_parser->getKey() !== 'net.tcp.service' && $this->item_key_parser->getKey() !== 'net.tcp.service.perf') { return $value; } if ($this->item_key_parser->getParamsNum() == 0 || $this->item_key_parser->getParam(0) !== 'ntp') { return $value; } return substr_replace($value, 'udp', 4, 3); }
/** * Check items data. * * Any system field passed to the function will be unset. * * @throw APIException * * @param array $items passed by reference * @param bool $update * * @return void */ protected function checkInput(array &$items, $update = false) { if ($update) { $itemDbFields = ['itemid' => null]; $dbItemsFields = ['itemid', 'templateid']; foreach ($this->fieldRules as $field => $rule) { if (!isset($rule['system'])) { $dbItemsFields[] = $field; } } $dbItems = $this->get(['output' => $dbItemsFields, 'itemids' => zbx_objectValues($items, 'itemid'), 'editable' => true, 'preservekeys' => true]); $dbHosts = API::Host()->get(['output' => ['hostid', 'status', 'name'], 'hostids' => zbx_objectValues($dbItems, 'hostid'), 'templated_hosts' => true, 'editable' => true, 'selectApplications' => ['applicationid', 'flags'], 'preservekeys' => true]); } else { $itemDbFields = ['name' => null, 'key_' => null, 'hostid' => null, 'type' => null, 'value_type' => null, 'delay' => '0', 'delay_flex' => '']; $dbHosts = API::Host()->get(['output' => ['hostid', 'status', 'name'], 'hostids' => zbx_objectValues($items, 'hostid'), 'templated_hosts' => true, 'editable' => true, 'selectApplications' => ['applicationid', 'flags'], 'preservekeys' => true]); } // interfaces $interfaces = API::HostInterface()->get(['output' => ['interfaceid', 'hostid', 'type'], 'hostids' => zbx_objectValues($dbHosts, 'hostid'), 'nopermissions' => true, 'preservekeys' => true]); if ($update) { $updateDiscoveredValidator = new CUpdateDiscoveredValidator(['allowed' => ['itemid', 'status'], 'messageAllowedField' => _('Cannot update "%2$s" for a discovered item "%1$s".')]); foreach ($items as $item) { // check permissions if (!isset($dbItems[$item['itemid']])) { self::exception(ZBX_API_ERROR_PARAMETERS, _('No permissions to referred object or it does not exist!')); } $dbItem = $dbItems[$item['itemid']]; $itemName = isset($item['name']) ? $item['name'] : $dbItem['name']; // discovered fields, except status, cannot be updated $updateDiscoveredValidator->setObjectName($itemName); $this->checkPartialValidator($item, $updateDiscoveredValidator, $dbItem); } $items = $this->extendObjects($this->tableName(), $items, ['name', 'flags']); } $item_key_parser = new CItemKey(); foreach ($items as $inum => &$item) { $item = $this->clearValues($item); $fullItem = $items[$inum]; if (!check_db_fields($itemDbFields, $item)) { self::exception(ZBX_API_ERROR_PARAMETERS, _('Incorrect arguments passed to function.')); } if ($update) { check_db_fields($dbItems[$item['itemid']], $fullItem); $this->checkNoParameters($item, ['templateid', 'state'], _('Cannot update "%1$s" for item "%2$s".'), $item['name']); // apply rules foreach ($this->fieldRules as $field => $rules) { if (0 != $fullItem['templateid'] && isset($rules['template']) || isset($rules['system'])) { unset($item[$field]); // For templated item and fields that should not be modified, use the value from DB. if (array_key_exists($field, $dbItems[$item['itemid']]) && array_key_exists($field, $fullItem)) { $fullItem[$field] = $dbItems[$item['itemid']][$field]; } } } if (!isset($item['key_'])) { $item['key_'] = $fullItem['key_']; } if (!isset($item['hostid'])) { $item['hostid'] = $fullItem['hostid']; } // if a templated item is being assigned to an interface with a different type, ignore it $itemInterfaceType = itemTypeInterface($dbItems[$item['itemid']]['type']); if ($fullItem['templateid'] && isset($item['interfaceid']) && isset($interfaces[$item['interfaceid']]) && $itemInterfaceType !== INTERFACE_TYPE_ANY && $interfaces[$item['interfaceid']]['type'] != $itemInterfaceType) { unset($item['interfaceid']); } } else { if (!isset($dbHosts[$item['hostid']])) { self::exception(ZBX_API_ERROR_PARAMETERS, _('No permissions to referred object or it does not exist!')); } check_db_fields($itemDbFields, $fullItem); $this->checkNoParameters($item, ['templateid', 'state'], _('Cannot set "%1$s" for item "%2$s".'), $item['name']); } $host = $dbHosts[$fullItem['hostid']]; if ($fullItem['type'] == ITEM_TYPE_ZABBIX_ACTIVE) { $item['delay_flex'] = ''; } if ($fullItem['value_type'] == ITEM_VALUE_TYPE_STR) { $item['delta'] = 0; } if ($fullItem['value_type'] != ITEM_VALUE_TYPE_UINT64) { $item['data_type'] = 0; } // For non-numeric types, whichever value was entered in trends field, is overwritten to zero. if ($fullItem['value_type'] == ITEM_VALUE_TYPE_STR || $fullItem['value_type'] == ITEM_VALUE_TYPE_LOG || $fullItem['value_type'] == ITEM_VALUE_TYPE_TEXT) { $item['trends'] = 0; } // check if the item requires an interface $itemInterfaceType = itemTypeInterface($fullItem['type']); if ($itemInterfaceType !== false && $host['status'] != HOST_STATUS_TEMPLATE) { if (!$fullItem['interfaceid']) { self::exception(ZBX_API_ERROR_PARAMETERS, _('No interface found.')); } elseif (!isset($interfaces[$fullItem['interfaceid']]) || bccomp($interfaces[$fullItem['interfaceid']]['hostid'], $fullItem['hostid']) != 0) { self::exception(ZBX_API_ERROR_PARAMETERS, _('Item uses host interface from non-parent host.')); } elseif ($itemInterfaceType !== INTERFACE_TYPE_ANY && $interfaces[$fullItem['interfaceid']]['type'] != $itemInterfaceType) { self::exception(ZBX_API_ERROR_PARAMETERS, _('Item uses incorrect interface type.')); } } else { $item['interfaceid'] = 0; } // item key if ($fullItem['type'] == ITEM_TYPE_DB_MONITOR) { if (!isset($fullItem['flags']) || $fullItem['flags'] != ZBX_FLAG_DISCOVERY_RULE) { if (strcmp($fullItem['key_'], ZBX_DEFAULT_KEY_DB_MONITOR) == 0) { self::exception(ZBX_API_ERROR_PARAMETERS, _('Check the key, please. Default example was passed.')); } } elseif ($fullItem['flags'] == ZBX_FLAG_DISCOVERY_RULE) { if (strcmp($fullItem['key_'], ZBX_DEFAULT_KEY_DB_MONITOR_DISCOVERY) == 0) { self::exception(ZBX_API_ERROR_PARAMETERS, _('Check the key, please. Default example was passed.')); } } } elseif ($fullItem['type'] == ITEM_TYPE_SSH && strcmp($fullItem['key_'], ZBX_DEFAULT_KEY_SSH) == 0 || $fullItem['type'] == ITEM_TYPE_TELNET && strcmp($fullItem['key_'], ZBX_DEFAULT_KEY_TELNET) == 0 || $fullItem['type'] == ITEM_TYPE_JMX && strcmp($fullItem['key_'], ZBX_DEFAULT_KEY_JMX) == 0) { self::exception(ZBX_API_ERROR_PARAMETERS, _('Check the key, please. Default example was passed.')); } // key if ($item_key_parser->parse($fullItem['key_']) != CParser::PARSE_SUCCESS) { self::exception(ZBX_API_ERROR_PARAMETERS, _params($this->getErrorMsg(self::ERROR_INVALID_KEY), [$fullItem['key_'], $fullItem['name'], $host['name'], $item_key_parser->getError()])); } // parameters if ($fullItem['type'] == ITEM_TYPE_AGGREGATE) { $params_num = $item_key_parser->getParamsNum(); if (!str_in_array($item_key_parser->getKey(), ['grpmax', 'grpmin', 'grpsum', 'grpavg']) || $params_num > 4 || $params_num < 3 || $params_num == 3 && $item_key_parser->getParam(2) !== 'last' || !str_in_array($item_key_parser->getParam(2), ['last', 'min', 'max', 'avg', 'sum', 'count'])) { self::exception(ZBX_API_ERROR_PARAMETERS, _s('Key "%1$s" does not match <grpmax|grpmin|grpsum|grpavg>["Host group(s)", "Item key",' . ' "<last|min|max|avg|sum|count>", "parameter"].', $item_key_parser->getKey())); } } // type of information if ($fullItem['type'] == ITEM_TYPE_AGGREGATE && $fullItem['value_type'] != ITEM_VALUE_TYPE_UINT64 && $fullItem['value_type'] != ITEM_VALUE_TYPE_FLOAT) { self::exception(ZBX_API_ERROR_PARAMETERS, _('Type of information must be "Numeric (unsigned)" or "Numeric (float)" for aggregate items.')); } // update interval if ($fullItem['type'] != ITEM_TYPE_TRAPPER && $fullItem['type'] != ITEM_TYPE_SNMPTRAP) { // delay must be between 0 and 86400, if delay is 0, delay_flex interval must be set. if ($fullItem['delay'] < 0 || $fullItem['delay'] > SEC_PER_DAY || $fullItem['delay'] == 0 && $fullItem['delay_flex'] === '') { self::exception(ZBX_API_ERROR_PARAMETERS, _('Item will not be refreshed. Please enter a correct update interval.')); } // Don't parse empty strings, they will not be valid. if ($fullItem['delay_flex'] === '') { continue; } // Validate item delay_flex string. First check syntax with parser, then validate time ranges. $item_delay_flex_parser = new CItemDelayFlexParser($fullItem['delay_flex']); if ($item_delay_flex_parser->isValid()) { $delay_flex_validator = new CItemDelayFlexValidator(); if ($delay_flex_validator->validate($item_delay_flex_parser->getIntervals())) { // Some valid intervals exist at this point. $flexible_intervals = $item_delay_flex_parser->getFlexibleIntervals(); // If there are no flexible intervals, skip the next check calculation. if (!$flexible_intervals) { continue; } $nextCheck = calculateItemNextCheck(0, $fullItem['delay'], $item_delay_flex_parser->getFlexibleIntervals($flexible_intervals), time()); if ($nextCheck == ZBX_JAN_2038) { self::exception(ZBX_API_ERROR_PARAMETERS, _('Item will not be refreshed. Please enter a correct update interval.')); } } else { self::exception(ZBX_API_ERROR_PARAMETERS, $delay_flex_validator->getError()); } } else { self::exception(ZBX_API_ERROR_PARAMETERS, _s('Invalid interval "%1$s": %2$s.', $fullItem['delay_flex'], $item_delay_flex_parser->getError())); } } // ssh, telnet if ($fullItem['type'] == ITEM_TYPE_SSH || $fullItem['type'] == ITEM_TYPE_TELNET) { if (zbx_empty($fullItem['username'])) { self::exception(ZBX_API_ERROR_PARAMETERS, _('No authentication user name specified.')); } if ($fullItem['type'] == ITEM_TYPE_SSH && $fullItem['authtype'] == ITEM_AUTHTYPE_PUBLICKEY) { if (zbx_empty($fullItem['publickey'])) { self::exception(ZBX_API_ERROR_PARAMETERS, _('No public key file specified.')); } if (zbx_empty($fullItem['privatekey'])) { self::exception(ZBX_API_ERROR_PARAMETERS, _('No private key file specified.')); } } } // snmp trap if ($fullItem['type'] == ITEM_TYPE_SNMPTRAP && $fullItem['key_'] !== 'snmptrap.fallback' && $item_key_parser->getKey() !== 'snmptrap') { self::exception(ZBX_API_ERROR_PARAMETERS, _('SNMP trap key is invalid.')); } // snmp oid if (in_array($fullItem['type'], [ITEM_TYPE_SNMPV1, ITEM_TYPE_SNMPV2C, ITEM_TYPE_SNMPV3]) && zbx_empty($fullItem['snmp_oid'])) { self::exception(ZBX_API_ERROR_PARAMETERS, _('No SNMP OID specified.')); } // snmp community if (in_array($fullItem['type'], [ITEM_TYPE_SNMPV1, ITEM_TYPE_SNMPV2C]) && zbx_empty($fullItem['snmp_community'])) { self::exception(ZBX_API_ERROR_PARAMETERS, _('No SNMP community specified.')); } // snmp port if (isset($fullItem['port']) && !zbx_empty($fullItem['port']) && !validatePortNumberOrMacro($fullItem['port'])) { self::exception(ZBX_API_ERROR_PARAMETERS, _s('Item "%1$s:%2$s" has invalid port: "%3$s".', $fullItem['name'], $fullItem['key_'], $fullItem['port'])); } if (isset($fullItem['snmpv3_securitylevel']) && $fullItem['snmpv3_securitylevel'] != ITEM_SNMPV3_SECURITYLEVEL_NOAUTHNOPRIV) { // snmpv3 authprotocol if (str_in_array($fullItem['snmpv3_securitylevel'], [ITEM_SNMPV3_SECURITYLEVEL_AUTHNOPRIV, ITEM_SNMPV3_SECURITYLEVEL_AUTHPRIV])) { if (isset($fullItem['snmpv3_authprotocol']) && (zbx_empty($fullItem['snmpv3_authprotocol']) || !str_in_array($fullItem['snmpv3_authprotocol'], [ITEM_AUTHPROTOCOL_MD5, ITEM_AUTHPROTOCOL_SHA]))) { self::exception(ZBX_API_ERROR_PARAMETERS, _s('Incorrect authentication protocol for item "%1$s".', $fullItem['name'])); } } // snmpv3 privprotocol if ($fullItem['snmpv3_securitylevel'] == ITEM_SNMPV3_SECURITYLEVEL_AUTHPRIV) { if (isset($fullItem['snmpv3_privprotocol']) && (zbx_empty($fullItem['snmpv3_privprotocol']) || !str_in_array($fullItem['snmpv3_privprotocol'], [ITEM_PRIVPROTOCOL_DES, ITEM_PRIVPROTOCOL_AES]))) { self::exception(ZBX_API_ERROR_PARAMETERS, _s('Incorrect privacy protocol for item "%1$s".', $fullItem['name'])); } } } if (isset($item['applications']) && $item['applications']) { /* * 'flags' is available for update and item prototypes. * Don't allow discovered or any other application types for item prototypes in 'applications' option. */ if (array_key_exists('flags', $fullItem) && $fullItem['flags'] == ZBX_FLAG_DISCOVERY_PROTOTYPE) { foreach ($host['applications'] as $num => $application) { if ($application['flags'] != ZBX_FLAG_DISCOVERY_NORMAL) { unset($host['applications'][$num]); } } } // check that the given applications belong to the item's host $dbApplicationIds = zbx_objectValues($host['applications'], 'applicationid'); foreach ($item['applications'] as $appId) { if (!in_array($appId, $dbApplicationIds)) { $error = _s('Application with ID "%1$s" is not available on "%2$s".', $appId, $host['name']); self::exception(ZBX_API_ERROR_PARAMETERS, $error); } } } $this->checkSpecificFields($fullItem); } unset($item); $this->checkExistingItems($items); }
/** * Resolve item name macros to "name_expanded" field. * * @param array $items * @param string $items[n]['itemid'] * @param string $items[n]['hostid'] * @param string $items[n]['name'] * @param string $items[n]['key_'] item key (optional) * but is (mandatory) if macros exist and "key_expanded" is not present * @param string $items[n]['key_expanded'] expanded item key (optional) * * @return array */ public function resolveItemNames(array $items) { foreach ($items as &$item) { $item['name_expanded'] = $item['name']; } unset($item); $types = ['usermacros' => true, 'references' => true]; $macro_values = []; $usermacros = []; foreach ($items as $key => $item) { $matched_macros = $this->extractMacros([$item['name_expanded']], $types); if ($matched_macros['usermacros']) { $usermacros[$key] = ['hostids' => [$item['hostid']], 'macros' => $matched_macros['usermacros']]; } if ($matched_macros['references']) { $macro_values[$key] = $matched_macros['references']; } } if ($macro_values) { $items_with_unresolved_keys = []; $expanded_keys = []; // Resolve macros in item key. foreach ($macro_values as $key => $macros) { if (!array_key_exists('key_expanded', $items[$key])) { $items_with_unresolved_keys[$key] = ['itemid' => $items[$key]['itemid'], 'hostid' => $items[$key]['hostid'], 'key_' => $items[$key]['key_']]; } else { $expanded_keys[$key] = $items[$key]['key_expanded']; } } if ($items_with_unresolved_keys) { foreach ($this->resolveItemKeys($items_with_unresolved_keys) as $key => $item) { $expanded_keys[$key] = $item['key_expanded']; } } $item_key_parser = new CItemKey(); foreach ($expanded_keys as $key => $expanded_key) { if ($item_key_parser->parse($expanded_key) == CParser::PARSE_SUCCESS) { foreach ($macro_values[$key] as $macro => &$value) { if (($param = $item_key_parser->getParam($macro[1] - 1)) !== null) { $value = $param; } } unset($value); } } } foreach ($this->getUserMacros($usermacros) as $key => $usermacros_data) { $macro_values[$key] = array_key_exists($key, $macro_values) ? array_merge($macro_values[$key], $usermacros_data['macros']) : $usermacros_data['macros']; } $types = $this->transformToPositionTypes($types); // Replace macros to value. foreach (array_keys($macro_values) as $key) { $matched_macros = $this->getMacroPositions($items[$key]['name_expanded'], $types); foreach (array_reverse($matched_macros, true) as $pos => $macro) { $items[$key]['name_expanded'] = substr_replace($items[$key]['name_expanded'], $macro_values[$key][$macro], $pos, strlen($macro)); } } return $items; }
/** * Update web scenario steps. * * @param $httpTest * @param $websteps * * @throws Exception */ protected function updateStepsReal($httpTest, $websteps) { $item_key_parser = new CItemKey(); // get all used keys $webstepids = zbx_objectValues($websteps, 'httpstepid'); $dbKeys = DBfetchArrayAssoc(DBselect('SELECT i.key_' . ' FROM items i,httpstepitem hi' . ' WHERE ' . dbConditionInt('hi.httpstepid', $webstepids) . ' AND hi.itemid=i.itemid'), 'key_'); foreach ($websteps as $webstep) { DB::update('httpstep', ['values' => $webstep, 'where' => ['httpstepid' => $webstep['httpstepid']]]); // update item keys $itemids = []; $stepitemsUpdate = $updateFields = []; $dbStepItems = DBselect('SELECT i.itemid,i.key_,hi.type' . ' FROM items i,httpstepitem hi' . ' WHERE hi.httpstepid=' . zbx_dbstr($webstep['httpstepid']) . ' AND hi.itemid=i.itemid'); while ($stepitem = DBfetch($dbStepItems)) { $itemids[] = $stepitem['itemid']; if (isset($httpTest['name']) || isset($webstep['name'])) { if (!isset($httpTest['name']) || !isset($webstep['name'])) { $item_key_parser->parse($stepitem['key_']); if (!isset($httpTest['name'])) { $httpTest['name'] = $item_key_parser->getParam(0); } if (!isset($webstep['name'])) { $webstep['name'] = $item_key_parser->getParam(1); } } $updateFields['key_'] = $this->getStepKey($stepitem['type'], $httpTest['name'], $webstep['name']); } if (isset($dbKeys[$updateFields['key_']])) { unset($updateFields['key_']); } if (isset($httpTest['status'])) { $updateFields['status'] = HTTPTEST_STATUS_ACTIVE == $httpTest['status'] ? ITEM_STATUS_ACTIVE : ITEM_STATUS_DISABLED; } if (isset($httpTest['delay'])) { $updateFields['delay'] = $httpTest['delay']; } if (!empty($updateFields)) { $stepitemsUpdate[] = ['values' => $updateFields, 'where' => ['itemid' => $stepitem['itemid']]]; } } DB::update('items', $stepitemsUpdate); if (isset($httpTest['applicationid'])) { $this->updateItemsApplications($itemids, $httpTest['applicationid']); } } }