You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1297 lines
45 KiB
1297 lines
45 KiB
<?php
|
|
/*
|
|
** Zabbix
|
|
** Copyright (C) 2001-2023 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 containing methods for operations with http tests.
|
|
*/
|
|
class CHttpTest extends CApiService {
|
|
|
|
public const ACCESS_RULES = [
|
|
'get' => ['min_user_type' => USER_TYPE_ZABBIX_USER],
|
|
'create' => ['min_user_type' => USER_TYPE_ZABBIX_ADMIN],
|
|
'update' => ['min_user_type' => USER_TYPE_ZABBIX_ADMIN],
|
|
'delete' => ['min_user_type' => USER_TYPE_ZABBIX_ADMIN]
|
|
];
|
|
|
|
protected $tableName = 'httptest';
|
|
protected $tableAlias = 'ht';
|
|
protected $sortColumns = ['httptestid', 'name'];
|
|
|
|
/**
|
|
* Get data about web scenarios.
|
|
*
|
|
* @param array $options
|
|
*
|
|
* @return array
|
|
*/
|
|
public function get($options = []) {
|
|
$result = [];
|
|
|
|
$sqlParts = [
|
|
'select' => ['httptests' => 'ht.httptestid'],
|
|
'from' => ['httptest' => 'httptest ht'],
|
|
'where' => [],
|
|
'group' => [],
|
|
'order' => [],
|
|
'limit' => null
|
|
];
|
|
|
|
$defOptions = [
|
|
'httptestids' => null,
|
|
'hostids' => null,
|
|
'groupids' => null,
|
|
'templateids' => null,
|
|
'editable' => false,
|
|
'inherited' => null,
|
|
'templated' => null,
|
|
'monitored' => null,
|
|
'nopermissions' => null,
|
|
'evaltype' => TAG_EVAL_TYPE_AND_OR,
|
|
'tags' => null,
|
|
// filter
|
|
'filter' => null,
|
|
'search' => null,
|
|
'searchByAny' => null,
|
|
'startSearch' => false,
|
|
'excludeSearch' => false,
|
|
// output
|
|
'output' => API_OUTPUT_EXTEND,
|
|
'expandName' => null,
|
|
'expandStepName' => null,
|
|
'selectHosts' => null,
|
|
'selectSteps' => null,
|
|
'selectTags' => null,
|
|
'countOutput' => false,
|
|
'groupCount' => false,
|
|
'preservekeys' => false,
|
|
'sortfield' => '',
|
|
'sortorder' => '',
|
|
'limit' => null
|
|
];
|
|
$options = zbx_array_merge($defOptions, $options);
|
|
|
|
// editable + PERMISSION CHECK
|
|
if (self::$userData['type'] != USER_TYPE_SUPER_ADMIN && !$options['nopermissions']) {
|
|
$permission = $options['editable'] ? PERM_READ_WRITE : PERM_READ;
|
|
$userGroups = getUserGroupsByUserId(self::$userData['userid']);
|
|
|
|
$sqlParts['where'][] = 'EXISTS ('.
|
|
'SELECT NULL'.
|
|
' FROM hosts_groups hgg'.
|
|
' JOIN rights r'.
|
|
' ON r.id=hgg.groupid'.
|
|
' AND '.dbConditionInt('r.groupid', $userGroups).
|
|
' WHERE ht.hostid=hgg.hostid'.
|
|
' GROUP BY hgg.hostid'.
|
|
' HAVING MIN(r.permission)>'.PERM_DENY.
|
|
' AND MAX(r.permission)>='.zbx_dbstr($permission).
|
|
')';
|
|
}
|
|
|
|
// httptestids
|
|
if (!is_null($options['httptestids'])) {
|
|
zbx_value2array($options['httptestids']);
|
|
|
|
$sqlParts['where']['httptestid'] = dbConditionInt('ht.httptestid', $options['httptestids']);
|
|
}
|
|
|
|
// templateids
|
|
if (!is_null($options['templateids'])) {
|
|
zbx_value2array($options['templateids']);
|
|
|
|
if (!is_null($options['hostids'])) {
|
|
zbx_value2array($options['hostids']);
|
|
$options['hostids'] = array_merge($options['hostids'], $options['templateids']);
|
|
}
|
|
else {
|
|
$options['hostids'] = $options['templateids'];
|
|
}
|
|
}
|
|
// hostids
|
|
if (!is_null($options['hostids'])) {
|
|
zbx_value2array($options['hostids']);
|
|
|
|
$sqlParts['where']['hostid'] = dbConditionInt('ht.hostid', $options['hostids']);
|
|
|
|
if ($options['groupCount']) {
|
|
$sqlParts['group']['hostid'] = 'ht.hostid';
|
|
}
|
|
}
|
|
|
|
// tags
|
|
if ($options['tags'] !== null && $options['tags']) {
|
|
$sqlParts['where'][] = CApiTagHelper::addWhereCondition($options['tags'], $options['evaltype'], 'ht',
|
|
'httptest_tag', 'httptestid'
|
|
);
|
|
}
|
|
|
|
// groupids
|
|
if (!is_null($options['groupids'])) {
|
|
zbx_value2array($options['groupids']);
|
|
|
|
$sqlParts['from']['hosts_groups'] = 'hosts_groups hg';
|
|
$sqlParts['where'][] = dbConditionInt('hg.groupid', $options['groupids']);
|
|
$sqlParts['where'][] = 'hg.hostid=ht.hostid';
|
|
|
|
if ($options['groupCount']) {
|
|
$sqlParts['group']['hg'] = 'hg.groupid';
|
|
}
|
|
}
|
|
|
|
// inherited
|
|
if (isset($options['inherited'])) {
|
|
$sqlParts['where'][] = $options['inherited'] ? 'ht.templateid IS NOT NULL' : 'ht.templateid IS NULL';
|
|
}
|
|
|
|
// templated
|
|
if (isset($options['templated'])) {
|
|
$sqlParts['from']['hosts'] = 'hosts h';
|
|
$sqlParts['where']['ha'] = 'h.hostid=ht.hostid';
|
|
if ($options['templated']) {
|
|
$sqlParts['where'][] = 'h.status='.HOST_STATUS_TEMPLATE;
|
|
}
|
|
else {
|
|
$sqlParts['where'][] = 'h.status<>'.HOST_STATUS_TEMPLATE;
|
|
}
|
|
}
|
|
|
|
// monitored
|
|
if (!is_null($options['monitored'])) {
|
|
$sqlParts['from']['hosts'] = 'hosts h';
|
|
$sqlParts['where']['hht'] = 'h.hostid=ht.hostid';
|
|
|
|
if ($options['monitored']) {
|
|
$sqlParts['where'][] = 'h.status='.HOST_STATUS_MONITORED;
|
|
$sqlParts['where'][] = 'ht.status='.ITEM_STATUS_ACTIVE;
|
|
}
|
|
else {
|
|
$sqlParts['where'][] = '(h.status<>'.HOST_STATUS_MONITORED.' OR ht.status<>'.ITEM_STATUS_ACTIVE.')';
|
|
}
|
|
}
|
|
|
|
// search
|
|
if (is_array($options['search'])) {
|
|
zbx_db_search('httptest ht', $options, $sqlParts);
|
|
}
|
|
|
|
// filter
|
|
if (is_array($options['filter'])) {
|
|
if (array_key_exists('delay', $options['filter']) && $options['filter']['delay'] !== null) {
|
|
$options['filter']['delay'] = getTimeUnitFilters($options['filter']['delay']);
|
|
}
|
|
|
|
$this->dbFilter('httptest ht', $options, $sqlParts);
|
|
}
|
|
|
|
// limit
|
|
if (zbx_ctype_digit($options['limit']) && $options['limit']) {
|
|
$sqlParts['limit'] = $options['limit'];
|
|
}
|
|
|
|
$sqlParts = $this->applyQueryOutputOptions($this->tableName(), $this->tableAlias(), $options, $sqlParts);
|
|
$sqlParts = $this->applyQuerySortOptions($this->tableName(), $this->tableAlias(), $options, $sqlParts);
|
|
$res = DBselect(self::createSelectQueryFromParts($sqlParts), $sqlParts['limit']);
|
|
while ($httpTest = DBfetch($res)) {
|
|
if ($options['countOutput']) {
|
|
if ($options['groupCount']) {
|
|
$result[] = $httpTest;
|
|
}
|
|
else {
|
|
$result = $httpTest['rowscount'];
|
|
}
|
|
}
|
|
else {
|
|
$result[$httpTest['httptestid']] = $httpTest;
|
|
}
|
|
}
|
|
|
|
if ($options['countOutput']) {
|
|
return $result;
|
|
}
|
|
|
|
if ($result) {
|
|
$result = $this->addRelatedObjects($options, $result);
|
|
|
|
// expandName
|
|
$nameRequested = (is_array($options['output']) && in_array('name', $options['output']))
|
|
|| $options['output'] == API_OUTPUT_EXTEND;
|
|
$expandName = $options['expandName'] !== null && $nameRequested;
|
|
|
|
// expandStepName
|
|
$stepNameRequested = $options['selectSteps'] == API_OUTPUT_EXTEND
|
|
|| (is_array($options['selectSteps']) && in_array('name', $options['selectSteps']));
|
|
$expandStepName = $options['expandStepName'] !== null && $stepNameRequested;
|
|
|
|
if ($expandName || $expandStepName) {
|
|
$result = resolveHttpTestMacros($result, $expandName, $expandStepName);
|
|
}
|
|
|
|
$result = $this->unsetExtraFields($result, ['hostid'], $options['output']);
|
|
}
|
|
|
|
// removing keys (hash -> array)
|
|
if (!$options['preservekeys']) {
|
|
$result = zbx_cleanHashes($result);
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Create web scenario.
|
|
*
|
|
* @param $httptests
|
|
*
|
|
* @return array
|
|
*
|
|
* @throws APIException
|
|
*/
|
|
public function create($httptests) {
|
|
$this->validateCreate($httptests);
|
|
|
|
$httptests = Manager::HttpTest()->persist($httptests);
|
|
|
|
$this->addAuditBulk(CAudit::ACTION_ADD, CAudit::RESOURCE_SCENARIO, $httptests);
|
|
|
|
return ['httptestids' => zbx_objectValues($httptests, 'httptestid')];
|
|
}
|
|
|
|
/**
|
|
* @param array $httptests
|
|
*
|
|
* @throws APIException if the input is invalid.
|
|
*/
|
|
protected function validateCreate(array &$httptests): void {
|
|
$api_input_rules = ['type' => API_OBJECTS, 'flags' => API_NOT_EMPTY | API_NORMALIZE, 'uniq' => [['hostid', 'name']], 'fields' => [
|
|
'hostid' => ['type' => API_ID, 'flags' => API_REQUIRED],
|
|
'uuid' => ['type' => API_ANY],
|
|
'name' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('httptest', 'name')],
|
|
'delay' => ['type' => API_TIME_UNIT, 'flags' => API_NOT_EMPTY | API_ALLOW_USER_MACRO, 'in' => '1:'.SEC_PER_DAY],
|
|
'retries' => ['type' => API_INT32, 'in' => '1:10'],
|
|
'agent' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httptest', 'agent')],
|
|
'http_proxy' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httptest', 'http_proxy')],
|
|
'variables' => ['type' => API_OBJECTS, 'uniq' => [['name']], 'fields' => [
|
|
'name' => ['type' => API_VARIABLE_NAME, 'flags' => API_REQUIRED, 'length' => DB::getFieldLength('httptest_field', 'name')],
|
|
'value' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'length' => DB::getFieldLength('httptest_field', 'value')]
|
|
]],
|
|
'headers' => ['type' => API_OBJECTS, 'fields' => [
|
|
'name' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('httptest_field', 'name')],
|
|
'value' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'length' => DB::getFieldLength('httptest_field', 'value')]
|
|
]],
|
|
'status' => ['type' => API_INT32, 'in' => implode(',', [HTTPTEST_STATUS_ACTIVE, HTTPTEST_STATUS_DISABLED])],
|
|
'authentication' => ['type' => API_INT32, 'in' => implode(',', [ZBX_HTTP_AUTH_NONE, ZBX_HTTP_AUTH_BASIC, ZBX_HTTP_AUTH_NTLM, ZBX_HTTP_AUTH_KERBEROS, ZBX_HTTP_AUTH_DIGEST])],
|
|
'http_user' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httptest', 'http_user')],
|
|
'http_password' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httptest', 'http_password')],
|
|
'verify_peer' => ['type' => API_INT32, 'in' => implode(',', [ZBX_HTTP_VERIFY_PEER_OFF, ZBX_HTTP_VERIFY_PEER_ON])],
|
|
'verify_host' => ['type' => API_INT32, 'in' => implode(',', [ZBX_HTTP_VERIFY_HOST_OFF, ZBX_HTTP_VERIFY_HOST_ON])],
|
|
'ssl_cert_file' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httptest', 'ssl_cert_file')],
|
|
'ssl_key_file' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httptest', 'ssl_key_file')],
|
|
'ssl_key_password' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httptest', 'ssl_key_password')],
|
|
'steps' => ['type' => API_OBJECTS, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'uniq' => [['name'], ['no']], 'fields' => [
|
|
'name' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('httpstep', 'name')],
|
|
'no' => ['type' => API_INT32, 'flags' => API_REQUIRED],
|
|
'url' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('httpstep', 'url')],
|
|
'query_fields' => ['type' => API_OBJECTS, 'fields' => [
|
|
'name' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('httpstep_field', 'name')],
|
|
'value' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'length' => DB::getFieldLength('httpstep_field', 'value')]
|
|
]],
|
|
'posts' => ['type' => API_HTTP_POST, 'length' => DB::getFieldLength('httpstep', 'posts'), 'name-length' => DB::getFieldLength('httpstep_field', 'name'), 'value-length' => DB::getFieldLength('httpstep_field', 'value')],
|
|
'variables' => ['type' => API_OBJECTS, 'uniq' => [['name']], 'fields' => [
|
|
'name' => ['type' => API_VARIABLE_NAME, 'flags' => API_REQUIRED, 'length' => DB::getFieldLength('httpstep_field', 'name')],
|
|
'value' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'length' => DB::getFieldLength('httpstep_field', 'value')]
|
|
]],
|
|
'headers' => ['type' => API_OBJECTS, 'fields' => [
|
|
'name' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('httpstep_field', 'name')],
|
|
'value' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'length' => DB::getFieldLength('httpstep_field', 'value')]
|
|
]],
|
|
'follow_redirects' => ['type' => API_INT32, 'in' => implode(',', [HTTPTEST_STEP_FOLLOW_REDIRECTS_OFF, HTTPTEST_STEP_FOLLOW_REDIRECTS_ON])],
|
|
'retrieve_mode' => ['type' => API_INT32, 'in' => implode(',', [HTTPTEST_STEP_RETRIEVE_MODE_CONTENT, HTTPTEST_STEP_RETRIEVE_MODE_HEADERS, HTTPTEST_STEP_RETRIEVE_MODE_BOTH])],
|
|
'timeout' => ['type' => API_TIME_UNIT, 'flags' => API_NOT_EMPTY | API_ALLOW_USER_MACRO, 'in' => '1:'.SEC_PER_HOUR],
|
|
'required' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httpstep', 'required')],
|
|
'status_codes' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httpstep', 'status_codes')]
|
|
]],
|
|
'tags' => ['type' => API_OBJECTS, 'uniq' => [['tag', 'value']], 'fields' => [
|
|
'tag' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('httptest_tag', 'tag')],
|
|
'value' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httptest_tag', 'value'), 'default' => DB::getDefault('httptest_tag', 'value')]
|
|
]]
|
|
]];
|
|
|
|
if (!CApiInputValidator::validate($api_input_rules, $httptests, '/', $error)) {
|
|
self::exception(ZBX_API_ERROR_PARAMETERS, $error);
|
|
}
|
|
|
|
$names_by_hostid = [];
|
|
|
|
foreach ($httptests as $httptest) {
|
|
$names_by_hostid[$httptest['hostid']][] = $httptest['name'];
|
|
}
|
|
|
|
$this->checkHostsAndTemplates($httptests, $db_hosts, $db_templates);
|
|
self::addHostStatus($httptests, $db_hosts, $db_templates);
|
|
|
|
self::validateUuid($httptests, $db_hosts + $db_templates);
|
|
|
|
self::addUuid($httptests, $db_templates);
|
|
|
|
self::checkUuidDuplicates($httptests);
|
|
$this->checkDuplicates($names_by_hostid);
|
|
$this->validateAuthParameters($httptests, __FUNCTION__);
|
|
$this->validateSslParameters($httptests, __FUNCTION__);
|
|
$this->validateSteps($httptests, __FUNCTION__);
|
|
}
|
|
|
|
/**
|
|
* @param array $httptests
|
|
* @param array $db_hosts
|
|
*
|
|
* @throws APIException
|
|
*/
|
|
private static function validateUuid(array $httptests, array $db_hosts): void {
|
|
foreach ($httptests as &$httptest) {
|
|
$httptest['host_status'] = array_key_exists('status', $db_hosts[$httptest['hostid']])
|
|
? $db_hosts[$httptest['hostid']]['status']
|
|
: HOST_STATUS_TEMPLATE;
|
|
}
|
|
unset($httptest);
|
|
|
|
$api_input_rules = ['type' => API_OBJECTS, 'flags' => API_ALLOW_UNEXPECTED, 'uniq' => [['uuid']], 'fields' => [
|
|
'host_status' => ['type' => API_ANY],
|
|
'uuid' => ['type' => API_MULTIPLE, 'rules' => [
|
|
['if' => ['field' => 'host_status', 'in' => HOST_STATUS_TEMPLATE], 'type' => API_UUID],
|
|
['else' => true, 'type' => API_STRING_UTF8, 'in' => DB::getDefault('httptest', 'uuid'), 'unset' => true]
|
|
]]
|
|
]];
|
|
|
|
if (!CApiInputValidator::validate($api_input_rules, $httptests, '/', $error)) {
|
|
self::exception(ZBX_API_ERROR_PARAMETERS, $error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add the UUID to those of the given web scenarios that belong to a template and don't have the 'uuid' parameter
|
|
* set.
|
|
*
|
|
* @param array $httptests
|
|
* @param array $db_templates
|
|
*/
|
|
private static function addUuid(array &$httptests, array $db_templates): void {
|
|
foreach ($httptests as &$httptest) {
|
|
if (array_key_exists($httptest['hostid'], $db_templates) && !array_key_exists('uuid', $httptest)) {
|
|
$httptest['uuid'] = generateUuidV4();
|
|
}
|
|
}
|
|
unset($httptest);
|
|
}
|
|
|
|
/**
|
|
* Verify web scenario UUIDs are not repeated.
|
|
*
|
|
* @param array $httptests
|
|
* @param array|null $db_httptests
|
|
*
|
|
* @throws APIException
|
|
*/
|
|
private static function checkUuidDuplicates(array $httptests, array $db_httptests = null): void {
|
|
$httptest_indexes = [];
|
|
|
|
foreach ($httptests as $i => $httptest) {
|
|
if (!array_key_exists('uuid', $httptest) || $httptest['uuid'] === '') {
|
|
continue;
|
|
}
|
|
|
|
if ($db_httptests === null || $httptest['uuid'] !== $db_httptests[$httptest['httptestid']]['uuid']) {
|
|
$httptest_indexes[$httptest['uuid']] = $i;
|
|
}
|
|
}
|
|
|
|
if (!$httptest_indexes) {
|
|
return;
|
|
}
|
|
|
|
$duplicates = DB::select('httptest', [
|
|
'output' => ['uuid'],
|
|
'filter' => [
|
|
'uuid' => array_keys($httptest_indexes)
|
|
],
|
|
'limit' => 1
|
|
]);
|
|
|
|
if ($duplicates) {
|
|
self::exception(ZBX_API_ERROR_PARAMETERS,
|
|
_s('Invalid parameter "%1$s": %2$s.', '/'.($httptest_indexes[$duplicates[0]['uuid']] + 1),
|
|
_('web scenario with the same UUID already exists')
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param array $httptests
|
|
*
|
|
* @return array
|
|
*/
|
|
public function update(array $httptests) {
|
|
$this->validateUpdate($httptests, $db_httptests);
|
|
|
|
Manager::HttpTest()->persist($httptests);
|
|
|
|
foreach ($db_httptests as &$db_httptest) {
|
|
unset($db_httptest['headers'], $db_httptest['variables'], $db_httptest['steps']);
|
|
}
|
|
unset($db_httptest);
|
|
|
|
$this->addAuditBulk(CAudit::ACTION_UPDATE, CAudit::RESOURCE_SCENARIO, $httptests, $db_httptests);
|
|
|
|
return ['httptestids' => zbx_objectValues($httptests, 'httptestid')];
|
|
}
|
|
|
|
/**
|
|
* @param array $httptests
|
|
* @param array $db_httptests
|
|
*
|
|
* @throws APIException if the input is invalid.
|
|
*/
|
|
protected function validateUpdate(array &$httptests, array &$db_httptests = null) {
|
|
$api_input_rules = ['type' => API_OBJECTS, 'flags' => API_NOT_EMPTY | API_NORMALIZE, 'uniq' => [['httptestid']], 'fields' => [
|
|
'uuid' => ['type' => API_ANY],
|
|
'httptestid' => ['type' => API_ID, 'flags' => API_REQUIRED],
|
|
'name' => ['type' => API_STRING_UTF8, 'flags' => API_NOT_EMPTY, 'length' => DB::getFieldLength('httptest', 'name')],
|
|
'delay' => ['type' => API_TIME_UNIT, 'flags' => API_NOT_EMPTY | API_ALLOW_USER_MACRO, 'in' => '1:'.SEC_PER_DAY],
|
|
'retries' => ['type' => API_INT32, 'in' => '1:10'],
|
|
'agent' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httptest', 'agent')],
|
|
'http_proxy' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httptest', 'http_proxy')],
|
|
'variables' => ['type' => API_OBJECTS, 'uniq' => [['name']], 'fields' => [
|
|
'name' => ['type' => API_VARIABLE_NAME, 'flags' => API_REQUIRED, 'length' => DB::getFieldLength('httptest_field', 'name')],
|
|
'value' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'length' => DB::getFieldLength('httptest_field', 'value')]
|
|
]],
|
|
'headers' => ['type' => API_OBJECTS, 'fields' => [
|
|
'name' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('httptest_field', 'name')],
|
|
'value' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'length' => DB::getFieldLength('httptest_field', 'value')]
|
|
]],
|
|
'status' => ['type' => API_INT32, 'in' => implode(',', [HTTPTEST_STATUS_ACTIVE, HTTPTEST_STATUS_DISABLED])],
|
|
'authentication' => ['type' => API_INT32, 'in' => implode(',', [ZBX_HTTP_AUTH_NONE, ZBX_HTTP_AUTH_BASIC, ZBX_HTTP_AUTH_NTLM, ZBX_HTTP_AUTH_KERBEROS, ZBX_HTTP_AUTH_DIGEST])],
|
|
'http_user' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httptest', 'http_user')],
|
|
'http_password' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httptest', 'http_password')],
|
|
'verify_peer' => ['type' => API_INT32, 'in' => implode(',', [ZBX_HTTP_VERIFY_PEER_OFF, ZBX_HTTP_VERIFY_PEER_ON])],
|
|
'verify_host' => ['type' => API_INT32, 'in' => implode(',', [ZBX_HTTP_VERIFY_HOST_OFF, ZBX_HTTP_VERIFY_HOST_ON])],
|
|
'ssl_cert_file' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httptest', 'ssl_cert_file')],
|
|
'ssl_key_file' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httptest', 'ssl_key_file')],
|
|
'ssl_key_password' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httptest', 'ssl_key_password')],
|
|
'steps' => ['type' => API_OBJECTS, 'flags' => API_NOT_EMPTY, 'uniq' => [['httpstepid'], ['name'], ['no']], 'fields' => [
|
|
'httpstepid' => ['type' => API_ID],
|
|
'name' => ['type' => API_STRING_UTF8, 'flags' => API_NOT_EMPTY, 'length' => DB::getFieldLength('httpstep', 'name')],
|
|
'no' => ['type' => API_INT32],
|
|
'url' => ['type' => API_STRING_UTF8, 'flags' => API_NOT_EMPTY, 'length' => DB::getFieldLength('httpstep', 'url')],
|
|
'query_fields' => ['type' => API_OBJECTS, 'fields' => [
|
|
'name' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('httpstep_field', 'name')],
|
|
'value' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'length' => DB::getFieldLength('httpstep_field', 'value')]
|
|
]],
|
|
'posts' => ['type' => API_HTTP_POST, 'length' => DB::getFieldLength('httpstep', 'posts'), 'name-length' => DB::getFieldLength('httpstep_field', 'name'), 'value-length' => DB::getFieldLength('httpstep_field', 'value')],
|
|
'variables' => ['type' => API_OBJECTS, 'uniq' => [['name']], 'fields' => [
|
|
'name' => ['type' => API_VARIABLE_NAME, 'flags' => API_REQUIRED, 'length' => DB::getFieldLength('httpstep_field', 'name')],
|
|
'value' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'length' => DB::getFieldLength('httpstep_field', 'value')]
|
|
]],
|
|
'headers' => ['type' => API_OBJECTS, 'fields' => [
|
|
'name' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('httpstep_field', 'name')],
|
|
'value' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'length' => DB::getFieldLength('httpstep_field', 'value')]
|
|
]],
|
|
'follow_redirects' => ['type' => API_INT32, 'in' => implode(',', [HTTPTEST_STEP_FOLLOW_REDIRECTS_OFF, HTTPTEST_STEP_FOLLOW_REDIRECTS_ON])],
|
|
'retrieve_mode' => ['type' => API_INT32, 'in' => implode(',', [HTTPTEST_STEP_RETRIEVE_MODE_CONTENT, HTTPTEST_STEP_RETRIEVE_MODE_HEADERS, HTTPTEST_STEP_RETRIEVE_MODE_BOTH])],
|
|
'timeout' => ['type' => API_TIME_UNIT, 'flags' => API_NOT_EMPTY | API_ALLOW_USER_MACRO, 'in' => '1:'.SEC_PER_HOUR],
|
|
'required' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httpstep', 'required')],
|
|
'status_codes' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httpstep', 'status_codes')]
|
|
]],
|
|
'tags' => ['type' => API_OBJECTS, 'uniq' => [['tag', 'value']], 'fields' => [
|
|
'tag' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('httptest_tag', 'tag')],
|
|
'value' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httptest_tag', 'value'), 'default' => DB::getDefault('httptest_tag', 'value')]
|
|
]]
|
|
]];
|
|
|
|
if (!CApiInputValidator::validate($api_input_rules, $httptests, '/', $error)) {
|
|
self::exception(ZBX_API_ERROR_PARAMETERS, $error);
|
|
}
|
|
|
|
// permissions
|
|
$db_httptests = $this->get([
|
|
'output' => ['uuid', 'httptestid', 'hostid', 'name', 'delay', 'retries', 'agent', 'http_proxy',
|
|
'status', 'authentication', 'http_user', 'http_password', 'verify_peer', 'verify_host',
|
|
'ssl_cert_file', 'ssl_key_file', 'ssl_key_password', 'templateid'
|
|
],
|
|
'selectSteps' => ['httpstepid', 'name', 'no', 'url', 'timeout', 'posts', 'required',
|
|
'status_codes', 'follow_redirects', 'retrieve_mode', 'post_type'
|
|
],
|
|
'selectHosts' => ['status'],
|
|
'httptestids' => zbx_objectValues($httptests, 'httptestid'),
|
|
'editable' => true,
|
|
'preservekeys' => true
|
|
]);
|
|
|
|
$db_hosts = [];
|
|
|
|
foreach ($db_httptests as &$db_httptest) {
|
|
$db_httptest['headers'] = [];
|
|
$db_httptest['variables'] = [];
|
|
$db_httptest['steps'] = zbx_toHash($db_httptest['steps'], 'httpstepid');
|
|
|
|
$db_hosts[$db_httptest['hostid']] = $db_httptest['hosts'][0]['status'] == HOST_STATUS_TEMPLATE
|
|
? []
|
|
: $db_httptest['hosts'][0];
|
|
}
|
|
unset($db_httptest);
|
|
|
|
$names_by_hostid = [];
|
|
|
|
foreach ($httptests as $httptest) {
|
|
if (!array_key_exists($httptest['httptestid'], $db_httptests)) {
|
|
self::exception(ZBX_API_ERROR_PERMISSIONS,
|
|
_('No permissions to referred object or it does not exist!')
|
|
);
|
|
}
|
|
|
|
$db_httptest = $db_httptests[$httptest['httptestid']];
|
|
|
|
if (array_key_exists('name', $httptest)) {
|
|
if ($db_httptest['templateid'] != 0) {
|
|
self::exception(ZBX_API_ERROR_PARAMETERS, _s(
|
|
'Cannot update a templated web scenario "%1$s": %2$s.', $httptest['name'],
|
|
_s('unexpected parameter "%1$s"', 'name')
|
|
));
|
|
}
|
|
|
|
if ($httptest['name'] !== $db_httptest['name']) {
|
|
$names_by_hostid[$db_httptest['hostid']][] = $httptest['name'];
|
|
}
|
|
}
|
|
}
|
|
|
|
$httptests = $this->extendObjectsByKey($httptests, $db_httptests, 'httptestid', ['hostid', 'name']);
|
|
|
|
// uniqueness
|
|
foreach ($httptests as &$httptest) {
|
|
$db_httptest = $db_httptests[$httptest['httptestid']];
|
|
|
|
if (array_key_exists('steps', $httptest)) {
|
|
// unexpected parameters for templated web scenario steps
|
|
if ($db_httptest['templateid'] != 0) {
|
|
foreach ($httptest['steps'] as $httpstep) {
|
|
foreach (['name', 'no'] as $field_name) {
|
|
if (array_key_exists($field_name, $httpstep)) {
|
|
self::exception(ZBX_API_ERROR_PARAMETERS, _s(
|
|
'Cannot update step for a templated web scenario "%1$s": %2$s.', $httptest['name'],
|
|
_s('unexpected parameter "%1$s"', $field_name)
|
|
));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$httptest['steps'] =
|
|
$this->extendObjectsByKey($httptest['steps'], $db_httptest['steps'], 'httpstepid', ['name']);
|
|
}
|
|
}
|
|
unset($httptest);
|
|
|
|
$api_input_rules = ['type' => API_OBJECTS, 'uniq' => [['hostid', 'name']], 'fields' => [
|
|
'hostid' => ['type' => API_ID],
|
|
'name' => ['type' => API_STRING_UTF8],
|
|
'steps' => ['type' => API_OBJECTS, 'uniq' => [['name']], 'fields' => [
|
|
'name' => ['type' => API_STRING_UTF8]
|
|
]]
|
|
]];
|
|
|
|
if (!CApiInputValidator::validateUniqueness($api_input_rules, $httptests, '/', $error)) {
|
|
self::exception(ZBX_API_ERROR_PARAMETERS, $error);
|
|
}
|
|
|
|
self::validateUuid($httptests, $db_hosts);
|
|
|
|
self::checkUuidDuplicates($httptests, $db_httptests);
|
|
|
|
// validation
|
|
if ($names_by_hostid) {
|
|
$this->checkDuplicates($names_by_hostid);
|
|
}
|
|
$this->validateAuthParameters($httptests, __FUNCTION__, $db_httptests);
|
|
$this->validateSslParameters($httptests, __FUNCTION__, $db_httptests);
|
|
$this->validateSteps($httptests, __FUNCTION__, $db_httptests);
|
|
|
|
return $httptests;
|
|
}
|
|
|
|
/**
|
|
* @param array $httptestids
|
|
*
|
|
* @return array
|
|
*/
|
|
public function delete(array $httptestids) {
|
|
$this->validateDelete($httptestids, $db_httptests);
|
|
|
|
self::deleteForce($db_httptests);
|
|
|
|
return ['httptestids' => $httptestids];
|
|
}
|
|
|
|
/**
|
|
* @param array $httptestids
|
|
* @param array|null $db_httptests
|
|
*/
|
|
private function validateDelete(array $httptestids, ?array &$db_httptests): void {
|
|
$api_input_rules = ['type' => API_IDS, 'flags' => API_NOT_EMPTY, 'uniq' => true];
|
|
|
|
if (!CApiInputValidator::validate($api_input_rules, $httptestids, '/', $error)) {
|
|
self::exception(ZBX_API_ERROR_PARAMETERS, $error);
|
|
}
|
|
|
|
$db_httptests = $this->get([
|
|
'output' => ['httptestid', 'name', 'templateid'],
|
|
'httptestids' => $httptestids,
|
|
'editable' => true,
|
|
'preservekeys' => true
|
|
]);
|
|
|
|
if (count($db_httptests) != count($httptestids)) {
|
|
self::exception(ZBX_API_ERROR_PERMISSIONS, _('No permissions to referred object or it does not exist!'));
|
|
}
|
|
|
|
foreach ($httptestids as $httptestid) {
|
|
if ($db_httptests[$httptestid]['templateid'] != 0) {
|
|
self::exception(ZBX_API_ERROR_PARAMETERS,
|
|
_s('Cannot delete templated web scenario "%1$s".', $db_httptests[$httptestid]['name'])
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param array $db_httptests
|
|
*/
|
|
public static function deleteForce(array $db_httptests): void {
|
|
self::addInheritedHttptests($db_httptests);
|
|
|
|
$del_httptestids = array_keys($db_httptests);
|
|
|
|
self::deleteAffectedItems($del_httptestids);
|
|
self::deleteAffectedSteps($del_httptestids);
|
|
|
|
DB::delete('httptest_field', ['httptestid' => $del_httptestids]);
|
|
DB::delete('httptest_tag', ['httptestid' => $del_httptestids]);
|
|
DB::update('httptest', [
|
|
'values' => ['templateid' => 0],
|
|
'where' => ['httptestid' => $del_httptestids]
|
|
]);
|
|
DB::delete('httptest', ['httptestid' => $del_httptestids]);
|
|
|
|
self::addAuditLog(CAudit::ACTION_DELETE, CAudit::RESOURCE_SCENARIO, $db_httptests);
|
|
}
|
|
|
|
/**
|
|
* Add the inherited web scenarios of the given web scenarios to the given web scenario array.
|
|
*
|
|
* @param array $db_httptests
|
|
*/
|
|
private static function addInheritedHttptests(array &$db_httptests): void {
|
|
$templateids = array_keys($db_httptests);
|
|
|
|
do {
|
|
$options = [
|
|
'output' => ['httptestid', 'name'],
|
|
'filter' => ['templateid' => $templateids]
|
|
];
|
|
$result = DBselect(DB::makeSql('httptest', $options));
|
|
|
|
$templateids = [];
|
|
|
|
while ($row = DBfetch($result)) {
|
|
if (!array_key_exists($row['httptestid'], $db_httptests)) {
|
|
$templateids[] = $row['httptestid'];
|
|
|
|
$db_httptests[$row['httptestid']] = $row;
|
|
}
|
|
}
|
|
} while ($templateids);
|
|
}
|
|
|
|
/**
|
|
* Delete items, which would remain without web scenarios after the given web scenarios deletion.
|
|
*
|
|
* @param array $del_httptestids
|
|
*/
|
|
private static function deleteAffectedItems(array $del_httptestids): void {
|
|
$db_items = DBfetchArrayAssoc(DBselect(
|
|
'SELECT hti.itemid,i.name'.
|
|
' FROM httptestitem hti,items i'.
|
|
' WHERE hti.itemid=i.itemid'.
|
|
' AND '.dbConditionId('hti.httptestid', $del_httptestids)
|
|
), 'itemid');
|
|
|
|
CItem::addInheritedItems($db_items);
|
|
DB::delete('httptestitem', ['itemid' => array_keys($db_items)]);
|
|
CItem::deleteForce($db_items);
|
|
}
|
|
|
|
/**
|
|
* Delete steps of the given web scenarios.
|
|
*
|
|
* @param array $del_httptestids
|
|
*/
|
|
private static function deleteAffectedSteps(array $del_httptestids): void {
|
|
$del_stepids = array_column(DB::select('httpstep', [
|
|
'output' => ['httpstepid'],
|
|
'filter' => ['httptestid' => $del_httptestids]
|
|
]), 'httpstepid');
|
|
|
|
self::deleteAffectedStepItems($del_stepids);
|
|
|
|
DB::delete('httpstep_field', ['httpstepid' => $del_stepids]);
|
|
DB::delete('httpstep', ['httpstepid' => $del_stepids]);
|
|
}
|
|
|
|
/**
|
|
* Delete items of the given web scenario steps.
|
|
*
|
|
* @param array $del_stepids
|
|
*/
|
|
private static function deleteAffectedStepItems(array $del_stepids): void {
|
|
$db_items = DBfetchArrayAssoc(DBselect(
|
|
'SELECT hsi.itemid,i.name'.
|
|
' FROM httpstepitem hsi,items i'.
|
|
' WHERE hsi.itemid=i.itemid'.
|
|
' AND '.dbConditionId('hsi.httpstepid', $del_stepids)
|
|
), 'itemid');
|
|
|
|
CItem::addInheritedItems($db_items);
|
|
DB::delete('httpstepitem', ['itemid' => array_keys($db_items)]);
|
|
CItem::deleteForce($db_items);
|
|
}
|
|
|
|
/**
|
|
* Check that host IDs of given web scenarios are valid.
|
|
* If host IDs are valid, $db_hosts and $db_templates parameters will be filled with found hosts and templates.
|
|
*
|
|
* @param array $httptests
|
|
* @param array|null $db_hosts
|
|
* @param array|null $db_templates
|
|
*
|
|
* @throws APIException
|
|
*/
|
|
protected static function checkHostsAndTemplates(array $httptests, array &$db_hosts = null,
|
|
array &$db_templates = null): void {
|
|
$hostids = array_unique(array_column($httptests, 'hostid'));
|
|
|
|
$db_templates = API::Template()->get([
|
|
'output' => [],
|
|
'templateids' => $hostids,
|
|
'editable' => true,
|
|
'preservekeys' => true
|
|
]);
|
|
|
|
$_hostids = array_diff($hostids, array_keys($db_templates));
|
|
|
|
$db_hosts = $_hostids
|
|
? API::Host()->get([
|
|
'output' => ['status'],
|
|
'hostids' => $_hostids,
|
|
'editable' => true,
|
|
'preservekeys' => true
|
|
])
|
|
: [];
|
|
|
|
if (count($db_templates) + count($db_hosts) != count($hostids)) {
|
|
self::exception(ZBX_API_ERROR_PARAMETERS, _('No permissions to referred object or it does not exist!'));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add host_status property to given web scenarios in accordance of given hosts and templates statuses.
|
|
*
|
|
* @param array $httptests
|
|
* @param array $db_hosts
|
|
* @param array $db_templates
|
|
*/
|
|
protected static function addHostStatus(array &$httptests, array $db_hosts, array $db_templates): void {
|
|
foreach ($httptests as &$httptest) {
|
|
if (array_key_exists($httptest['hostid'], $db_templates)) {
|
|
$httptest['host_status'] = HOST_STATUS_TEMPLATE;
|
|
}
|
|
else {
|
|
$httptest['host_status'] = $db_hosts[$httptest['hostid']]['status'];
|
|
}
|
|
}
|
|
unset($httptest);
|
|
}
|
|
|
|
/**
|
|
* Check for duplicated web scenarios.
|
|
*
|
|
* @param array $names_by_hostid
|
|
*
|
|
* @throws APIException if web scenario already exists.
|
|
*/
|
|
private function checkDuplicates(array $names_by_hostid) {
|
|
$sql_where = [];
|
|
foreach ($names_by_hostid as $hostid => $names) {
|
|
$sql_where[] = '(ht.hostid='.$hostid.' AND '.dbConditionString('ht.name', $names).')';
|
|
}
|
|
|
|
$db_httptests = DBfetchArray(
|
|
DBselect('SELECT ht.name FROM httptest ht WHERE '.implode(' OR ', $sql_where), 1)
|
|
);
|
|
|
|
if ($db_httptests) {
|
|
self::exception(ZBX_API_ERROR_PARAMETERS,
|
|
_s('Web scenario "%1$s" already exists.', $db_httptests[0]['name'])
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param array $httptests
|
|
* @param string $method
|
|
* @param array $db_httptests
|
|
*
|
|
* @throws APIException
|
|
*/
|
|
protected function validateSteps(array &$httptests, $method, array $db_httptests = null) {
|
|
if ($method === 'validateUpdate') {
|
|
foreach ($httptests as $httptest) {
|
|
if (!array_key_exists('steps', $httptest)) {
|
|
continue;
|
|
}
|
|
|
|
$db_httptest = $db_httptests[$httptest['httptestid']];
|
|
|
|
if ($db_httptest['templateid'] != 0 && count($httptest['steps']) != count($db_httptest['steps'])) {
|
|
self::exception(ZBX_API_ERROR_PARAMETERS, _('Incorrect templated web scenario step count.'));
|
|
}
|
|
|
|
foreach ($httptest['steps'] as $step) {
|
|
if (!array_key_exists('httpstepid', $step)) {
|
|
if ($db_httptest['templateid'] == 0) {
|
|
continue;
|
|
}
|
|
else {
|
|
self::exception(ZBX_API_ERROR_PARAMETERS, _s(
|
|
'Cannot update step for a templated web scenario "%1$s": %2$s.', $httptest['name'],
|
|
_s('the parameter "%1$s" is missing', 'httpstepid')
|
|
));
|
|
}
|
|
}
|
|
|
|
if (!array_key_exists($step['httpstepid'], $db_httptest['steps'])) {
|
|
self::exception(ZBX_API_ERROR_PARAMETERS,
|
|
_('No permissions to referred object or it does not exist!')
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$this->checkStatusCodes($httptests);
|
|
$this->validateRetrieveMode($httptests, $method, $db_httptests);
|
|
}
|
|
|
|
/**
|
|
* Validate http response code range.
|
|
* Range can be empty string or list of comma separated numeric strings or user macros.
|
|
*
|
|
* Examples: '100-199, 301, 404, 500-550, {$MACRO}-200, {$MACRO}-{$MACRO}'
|
|
*
|
|
* @param array $httptests
|
|
*
|
|
* @throws APIException if the status code range is invalid.
|
|
*/
|
|
private function checkStatusCodes(array $httptests) {
|
|
$ranges_parser = new CRangesParser(['usermacros' => true]);
|
|
|
|
foreach ($httptests as $httptest) {
|
|
if (!array_key_exists('steps', $httptest)) {
|
|
continue;
|
|
}
|
|
|
|
foreach ($httptest['steps'] as $httpstep) {
|
|
if (!array_key_exists('status_codes', $httpstep) || $httpstep['status_codes'] === '') {
|
|
continue;
|
|
}
|
|
|
|
if ($ranges_parser->parse($httpstep['status_codes']) != CParser::PARSE_SUCCESS) {
|
|
self::exception(ZBX_API_ERROR_PARAMETERS,
|
|
_s('Invalid response code "%1$s".', $httpstep['status_codes'])
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
protected function applyQueryOutputOptions($tableName, $tableAlias, array $options, array $sqlParts) {
|
|
$sqlParts = parent::applyQueryOutputOptions($tableName, $tableAlias, $options, $sqlParts);
|
|
|
|
if (!$options['countOutput']) {
|
|
// make sure we request the hostid to be able to expand macros
|
|
if ($options['expandName'] !== null || $options['expandStepName'] !== null || $options['selectHosts'] !== null) {
|
|
$sqlParts = $this->addQuerySelect($this->fieldId('hostid'), $sqlParts);
|
|
}
|
|
}
|
|
|
|
return $sqlParts;
|
|
}
|
|
|
|
protected function addRelatedObjects(array $options, array $result) {
|
|
$result = parent::addRelatedObjects($options, $result);
|
|
|
|
$httpTestIds = array_keys($result);
|
|
|
|
// adding headers and variables
|
|
$fields = [
|
|
ZBX_HTTPFIELD_HEADER => 'headers',
|
|
ZBX_HTTPFIELD_VARIABLE => 'variables'
|
|
];
|
|
foreach ($fields as $type => $field) {
|
|
if (!$this->outputIsRequested($field, $options['output'])) {
|
|
unset($fields[$type]);
|
|
}
|
|
}
|
|
|
|
if ($fields) {
|
|
$db_httpfields = DB::select('httptest_field', [
|
|
'output' => ['httptestid', 'name', 'value', 'type'],
|
|
'filter' => [
|
|
'httptestid' => $httpTestIds,
|
|
'type' => array_keys($fields)
|
|
],
|
|
'sortfield' => ['httptest_fieldid']
|
|
]);
|
|
|
|
foreach ($result as &$httptest) {
|
|
foreach ($fields as $field) {
|
|
$httptest[$field] = [];
|
|
}
|
|
}
|
|
unset($httptest);
|
|
|
|
foreach ($db_httpfields as $db_httpfield) {
|
|
$result[$db_httpfield['httptestid']][$fields[$db_httpfield['type']]][] = [
|
|
'name' => $db_httpfield['name'],
|
|
'value' => $db_httpfield['value']
|
|
];
|
|
}
|
|
}
|
|
|
|
// adding hosts
|
|
if ($options['selectHosts'] !== null && $options['selectHosts'] != API_OUTPUT_COUNT) {
|
|
$relationMap = $this->createRelationMap($result, 'httptestid', 'hostid');
|
|
$hosts = API::Host()->get([
|
|
'output' => $options['selectHosts'],
|
|
'hostid' => $relationMap->getRelatedIds(),
|
|
'nopermissions' => true,
|
|
'templated_hosts' => true,
|
|
'preservekeys' => true
|
|
]);
|
|
$result = $relationMap->mapMany($result, $hosts, 'hosts');
|
|
}
|
|
|
|
// adding steps
|
|
if ($options['selectSteps'] !== null) {
|
|
if ($options['selectSteps'] != API_OUTPUT_COUNT) {
|
|
$fields = [
|
|
ZBX_HTTPFIELD_HEADER => 'headers',
|
|
ZBX_HTTPFIELD_VARIABLE => 'variables',
|
|
ZBX_HTTPFIELD_QUERY_FIELD => 'query_fields',
|
|
ZBX_HTTPFIELD_POST_FIELD => 'posts'
|
|
];
|
|
foreach ($fields as $type => $field) {
|
|
if (!$this->outputIsRequested($field, $options['selectSteps'])) {
|
|
unset($fields[$type]);
|
|
}
|
|
}
|
|
|
|
$db_httpsteps = API::getApiService()->select('httpstep', [
|
|
'output' => $this->outputExtend($options['selectSteps'], ['httptestid', 'httpstepid', 'post_type']),
|
|
'filter' => ['httptestid' => $httpTestIds],
|
|
'preservekeys' => true
|
|
]);
|
|
$relationMap = $this->createRelationMap($db_httpsteps, 'httptestid', 'httpstepid');
|
|
|
|
if ($fields) {
|
|
foreach ($db_httpsteps as &$db_httpstep) {
|
|
foreach ($fields as $type => $field) {
|
|
if ($type != ZBX_HTTPFIELD_POST_FIELD || $db_httpstep['post_type'] == ZBX_POSTTYPE_FORM) {
|
|
$db_httpstep[$field] = [];
|
|
}
|
|
}
|
|
}
|
|
unset($db_httpstep);
|
|
|
|
$db_httpstep_fields = DB::select('httpstep_field', [
|
|
'output' => ['httpstepid', 'name', 'value', 'type'],
|
|
'filter' => [
|
|
'httpstepid' => array_keys($db_httpsteps),
|
|
'type' => array_keys($fields)
|
|
],
|
|
'sortfield' => ['httpstep_fieldid']
|
|
]);
|
|
|
|
foreach ($db_httpstep_fields as $db_httpstep_field) {
|
|
$db_httpstep = &$db_httpsteps[$db_httpstep_field['httpstepid']];
|
|
|
|
if ($db_httpstep_field['type'] != ZBX_HTTPFIELD_POST_FIELD
|
|
|| $db_httpstep['post_type'] == ZBX_POSTTYPE_FORM) {
|
|
$db_httpstep[$fields[$db_httpstep_field['type']]][] = [
|
|
'name' => $db_httpstep_field['name'],
|
|
'value' => $db_httpstep_field['value']
|
|
];
|
|
}
|
|
}
|
|
unset($db_httpstep);
|
|
}
|
|
|
|
$db_httpsteps = $this->unsetExtraFields($db_httpsteps, ['httptestid', 'httpstepid', 'post_type'],
|
|
$options['selectSteps']
|
|
);
|
|
$result = $relationMap->mapMany($result, $db_httpsteps, 'steps');
|
|
}
|
|
else {
|
|
$dbHttpSteps = DBselect(
|
|
'SELECT hs.httptestid,COUNT(hs.httpstepid) AS stepscnt'.
|
|
' FROM httpstep hs'.
|
|
' WHERE '.dbConditionInt('hs.httptestid', $httpTestIds).
|
|
' GROUP BY hs.httptestid'
|
|
);
|
|
while ($dbHttpStep = DBfetch($dbHttpSteps)) {
|
|
$result[$dbHttpStep['httptestid']]['steps'] = $dbHttpStep['stepscnt'];
|
|
}
|
|
}
|
|
}
|
|
|
|
// Adding web scenario tags.
|
|
if ($options['selectTags'] !== null) {
|
|
$options['selectTags'] = ($options['selectTags'] !== API_OUTPUT_EXTEND)
|
|
? (array) $options['selectTags']
|
|
: ['tag', 'value'];
|
|
|
|
$options['selectTags'] = array_intersect(['tag', 'value'], $options['selectTags']);
|
|
$requested_output = array_flip($options['selectTags']);
|
|
|
|
$db_tags = DBselect(
|
|
'SELECT '.implode(',', array_merge($options['selectTags'], ['httptestid'])).
|
|
' FROM httptest_tag'.
|
|
' WHERE '.dbConditionInt('httptestid', $httpTestIds)
|
|
);
|
|
|
|
array_walk($result, function (&$http_test) {
|
|
$http_test['tags'] = [];
|
|
});
|
|
|
|
while ($db_tag = DBfetch($db_tags)) {
|
|
$result[$db_tag['httptestid']]['tags'][] = array_intersect_key($db_tag, $requested_output);
|
|
}
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* @param array $httptests
|
|
* @param string $method
|
|
* @param array $db_httptests
|
|
*
|
|
* @throws APIException if auth parameters are invalid.
|
|
*/
|
|
private function validateAuthParameters(array &$httptests, $method, array $db_httptests = null) {
|
|
foreach ($httptests as &$httptest) {
|
|
if (array_key_exists('authentication', $httptest) || array_key_exists('http_user', $httptest)
|
|
|| array_key_exists('http_password', $httptest)) {
|
|
$httptest += [
|
|
'authentication' => ($method === 'validateUpdate')
|
|
? $db_httptests[$httptest['httptestid']]['authentication']
|
|
: ZBX_HTTP_AUTH_NONE
|
|
];
|
|
|
|
if ($httptest['authentication'] == ZBX_HTTP_AUTH_NONE) {
|
|
foreach (['http_user', 'http_password'] as $field_name) {
|
|
$httptest += [$field_name => ''];
|
|
|
|
if ($httptest[$field_name] !== '') {
|
|
self::exception(ZBX_API_ERROR_PARAMETERS,
|
|
_s('Incorrect value for field "%1$s": %2$s.', $field_name, _('should be empty'))
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
unset($httptest);
|
|
}
|
|
|
|
/**
|
|
* @param array $httptests
|
|
* @param string $method
|
|
* @param array $db_httptests
|
|
*
|
|
* @throws APIException if SSL cert is present but SSL key is not.
|
|
*/
|
|
private function validateSslParameters(array &$httptests, $method, array $db_httptests = null) {
|
|
foreach ($httptests as &$httptest) {
|
|
if (array_key_exists('ssl_key_password', $httptest)
|
|
|| array_key_exists('ssl_key_file', $httptest)
|
|
|| array_key_exists('ssl_cert_file', $httptest)) {
|
|
if ($method === 'validateCreate') {
|
|
$httptest += [
|
|
'ssl_key_password' => '',
|
|
'ssl_key_file' => '',
|
|
'ssl_cert_file' => ''
|
|
];
|
|
}
|
|
else {
|
|
$db_httptest = $db_httptests[$httptest['httptestid']];
|
|
$httptest += [
|
|
'ssl_key_password' => $db_httptest['ssl_key_password'],
|
|
'ssl_key_file' => $db_httptest['ssl_key_file'],
|
|
'ssl_cert_file' => $db_httptest['ssl_cert_file']
|
|
];
|
|
}
|
|
|
|
if ($httptest['ssl_key_password'] != '' && $httptest['ssl_key_file'] == '') {
|
|
self::exception(ZBX_API_ERROR_PARAMETERS,
|
|
_s('Empty SSL key file for web scenario "%1$s".', $httptest['name'])
|
|
);
|
|
}
|
|
|
|
if ($httptest['ssl_key_file'] != '' && $httptest['ssl_cert_file'] == '') {
|
|
self::exception(ZBX_API_ERROR_PARAMETERS,
|
|
_s('Empty SSL certificate file for web scenario "%1$s".', $httptest['name'])
|
|
);
|
|
}
|
|
}
|
|
}
|
|
unset($httptest);
|
|
}
|
|
|
|
/**
|
|
* @param array $httptests
|
|
* @param string $method
|
|
* @param array $db_httptests
|
|
*
|
|
* @throws APIException if parameters is invalid.
|
|
*/
|
|
private function validateRetrieveMode(array &$httptests, $method, array $db_httptests = null) {
|
|
foreach ($httptests as &$httptest) {
|
|
if (!array_key_exists('steps', $httptest)) {
|
|
continue;
|
|
}
|
|
|
|
foreach ($httptest['steps'] as &$httpstep) {
|
|
if (array_key_exists('retrieve_mode', $httpstep)
|
|
|| array_key_exists('posts', $httpstep)
|
|
|| array_key_exists('required', $httpstep)) {
|
|
|
|
if ($method === 'validateCreate' || !array_key_exists('httpstepid', $httpstep)) {
|
|
$httpstep += [
|
|
'retrieve_mode' => HTTPTEST_STEP_RETRIEVE_MODE_CONTENT,
|
|
'posts' => '',
|
|
'required' => ''
|
|
];
|
|
}
|
|
else {
|
|
$db_httptest = $db_httptests[$httptest['httptestid']];
|
|
$db_httpstep = $db_httptest['steps'][$httpstep['httpstepid']];
|
|
$httpstep += [
|
|
'retrieve_mode' => $db_httpstep['retrieve_mode'],
|
|
'required' => $db_httpstep['required'],
|
|
'posts' => ($db_httpstep['retrieve_mode'] != HTTPTEST_STEP_RETRIEVE_MODE_HEADERS)
|
|
? $db_httpstep['posts']
|
|
: ''
|
|
];
|
|
}
|
|
|
|
if ($httpstep['retrieve_mode'] == HTTPTEST_STEP_RETRIEVE_MODE_HEADERS) {
|
|
if ($httpstep['posts'] !== '' && $httpstep['posts'] !== []) {
|
|
$field_name = $httpstep['required'] !== '' ? 'required' : 'posts';
|
|
|
|
self::exception(ZBX_API_ERROR_PARAMETERS,
|
|
_s('Incorrect value for field "%1$s": %2$s.', 'posts', _('should be empty'))
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
unset($httpstep);
|
|
}
|
|
unset($httptest);
|
|
}
|
|
|
|
/**
|
|
* @param array $templateids
|
|
* @param array|null $hostids
|
|
*/
|
|
public static function unlinkTemplateObjects(array $templateids, array $hostids = null): void {
|
|
$hostids_condition = $hostids ? ' AND '.dbConditionId('hht.hostid', $hostids) : '';
|
|
|
|
$result = DBselect(
|
|
'SELECT hht.httptestid,hht.name,h.status AS host_status'.
|
|
' FROM httptest ht,httptest hht,hosts h'.
|
|
' WHERE ht.httptestid=hht.templateid'.
|
|
' AND hht.hostid=h.hostid'.
|
|
' AND '.dbConditionId('ht.hostid', $templateids).
|
|
$hostids_condition
|
|
);
|
|
|
|
$httptests = [];
|
|
|
|
while ($row = DBfetch($result)) {
|
|
$httptest = [
|
|
'httptestid' => $row['httptestid'],
|
|
'name' => $row['name'],
|
|
'templateid' => 0
|
|
];
|
|
|
|
if ($row['host_status'] == HOST_STATUS_TEMPLATE) {
|
|
$httptest += ['uuid' => generateUuidV4()];
|
|
}
|
|
|
|
$httptests[] = $httptest;
|
|
}
|
|
|
|
if ($httptests) {
|
|
Manager::HttpTest()->update($httptests);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param array $templateids
|
|
* @param array|null $hostids
|
|
*/
|
|
public static function clearTemplateObjects(array $templateids, array $hostids = null): void {
|
|
$hostids_condition = $hostids ? ' AND '.dbConditionId('hht.hostid', $hostids) : '';
|
|
|
|
$db_httptests = DBfetchArrayAssoc(DBselect(
|
|
'SELECT hht.httptestid,hht.name'.
|
|
' FROM httptest ht,httptest hht'.
|
|
' WHERE ht.httptestid=hht.templateid'.
|
|
' AND '.dbConditionId('ht.hostid', $templateids).
|
|
$hostids_condition
|
|
), 'httptestid');
|
|
|
|
if ($db_httptests) {
|
|
self::deleteForce($db_httptests);
|
|
}
|
|
}
|
|
}
|