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.

1848 lines
51 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 to perform low level http tests related actions.
*/
class CHttpTestManager {
const ITEM_HISTORY = '30d';
const ITEM_TRENDS = '90d';
/**
* Changed steps names.
* array(
* testid1 => array(nameold1 => namenew1, nameold2 => namenew2),
* ...
* )
*
* @var array
*/
protected $changedSteps = [];
/**
* Map of parent http test id to child http test id.
*
* @var array
*/
protected $httpTestParents = [];
/**
* Array of parent item IDs indexed by parent httptest ID and item key.
*
* @var array
*/
private static $parent_itemids = [];
/**
* Save http test to db.
*
* @param array $httpTests
*
* @return array
*/
public function persist(array $httpTests) {
$this->changedSteps = $this->findChangedStepNames($httpTests);
$httpTests = $this->save($httpTests);
$this->inherit($httpTests);
return $httpTests;
}
/**
* Find steps where name was changed.
*
* @return array
*/
protected function findChangedStepNames(array $httpTests) {
$httpSteps = [];
$result = [];
foreach ($httpTests as $httpTest) {
if (isset($httpTest['httptestid']) && isset($httpTest['steps'])) {
foreach ($httpTest['steps'] as $step) {
if (isset($step['httpstepid']) && isset($step['name'])) {
$httpSteps[$step['httpstepid']] = $step['name'];
}
}
}
}
if (!empty($httpSteps)) {
$dbCursor = DBselect(
'SELECT hs.httpstepid,hs.httptestid,hs.name'.
' FROM httpstep hs'.
' WHERE '.dbConditionInt('hs.httpstepid', array_keys($httpSteps))
);
while ($dbStep = DBfetch($dbCursor)) {
if ($httpSteps[$dbStep['httpstepid']] != $dbStep['name']) {
$result[$dbStep['httptestid']][$httpSteps[$dbStep['httpstepid']]] = $dbStep['name'];
}
}
}
return $result;
}
/**
* Create new HTTP tests.
*
* @param array $httptests
*
* @return array
*/
public function create(array $httptests) {
$httptestids = DB::insert('httptest', $httptests);
foreach ($httptests as &$httptest) {
$httptest['httptestid'] = array_shift($httptestids);
}
unset($httptest);
self::createItems($httptests);
self::updateFields($httptests);
self::updateSteps($httptests);
self::updateTags($httptests);
return $httptests;
}
/**
* Update http tests.
*
* @param array $httptests
*
* @return array
*/
public function update(array $httptests) {
$db_httptests = DBfetchArrayAssoc(DBselect(
'SELECT ht.httptestid,ht.name,ht.delay,ht.retries,ht.agent,ht.http_proxy,ht.status,ht.authentication,'.
'ht.http_user,ht.http_password,ht.verify_peer,ht.verify_host,ht.ssl_cert_file,ht.ssl_key_file,'.
'ht.ssl_key_password,ht.hostid,ht.templateid,h.status AS host_status'.
' FROM httptest ht,hosts h'.
' WHERE ht.hostid=h.hostid'.
' AND '.dbConditionId('ht.httptestid', array_column($httptests, 'httptestid'))
), 'httptestid');
self::addAffectedObjects($httptests, $db_httptests);
$upd_httptests = [];
foreach ($httptests as $httptest) {
$upd_httptest = DB::getUpdatedValues('httptest', $httptest, $db_httptests[$httptest['httptestid']]);
if ($upd_httptest) {
$upd_httptests[] = [
'values' => $upd_httptest,
'where' => ['httptestid' => $httptest['httptestid']]
];
}
}
if ($upd_httptests) {
DB::update('httptest', $upd_httptests);
}
self::updateItems($httptests, $db_httptests);
self::updateFields($httptests, $db_httptests);
self::updateSteps($httptests, $db_httptests);
self::updateTags($httptests, $db_httptests);
return $httptests;
}
/**
* @param array $httptests
* @param array $db_httptests
*/
private static function addAffectedObjects(array $httptests, array &$db_httptests): void {
self::addAffectedItems($httptests, $db_httptests);
self::addAffectedFields($httptests, $db_httptests);
self::addAffectedSteps($httptests, $db_httptests);
self::addAffectedTags($httptests, $db_httptests);
}
/**
* @param array $httptests
* @param array $db_httptests
*/
private static function addAffectedItems(array $httptests, array &$db_httptests): void {
$httptestids = [];
foreach ($httptests as $httptest) {
$db_httptest = $db_httptests[$httptest['httptestid']];
$name_updated = $httptest['name'] != $db_httptest['name'];
$status_updated = array_key_exists('status', $httptest) && $httptest['status'] != $db_httptest['status'];
$delay_updated = array_key_exists('delay', $httptest) && $httptest['delay'] !== $db_httptest['delay'];
$templateid_updated = array_key_exists('templateid', $httptest)
&& bccomp($httptest['templateid'], $db_httptest['templateid']) != 0;
if ($name_updated || $status_updated || $delay_updated || $templateid_updated
|| array_key_exists('tags', $httptest)) {
$httptestids[] = $httptest['httptestid'];
}
}
if (!$httptestids) {
return;
}
$result = DBselect(
'SELECT hi.httptestid,hi.itemid,hi.type AS test_type,i.name,i.key_,i.status,i.delay,i.templateid'.
' FROM httptestitem hi,items i'.
' WHERE hi.itemid=i.itemid'.
' AND '.dbConditionId('hi.httptestid', $httptestids)
);
while ($row = DBfetch($result)) {
$db_httptests[$row['httptestid']]['items'][$row['itemid']] =
array_diff_key($row, array_flip(['httptestid']));
}
self::addAffectedItemTags($httptests, $db_httptests);
}
/**
* @param array $httptests
* @param array $db_httptests
*/
private static function addAffectedItemTags(array $httptests, array &$db_httptests): void {
$httptestids = [];
foreach ($httptests as $httptest) {
if (!array_key_exists('tags', $httptest)) {
continue;
}
$httptestids[] = $httptest['httptestid'];
foreach ($db_httptests[$httptest['httptestid']]['items'] as &$db_item) {
$db_item['tags'] = [];
}
unset($db_item);
}
if (!$httptestids) {
return;
}
$result = DBselect(
'SELECT hti.httptestid,hti.itemid,it.itemtagid,it.tag,it.value'.
' FROM httptestitem hti,item_tag it'.
' WHERE hti.itemid=it.itemid'.
' AND '.dbConditionId('hti.httptestid', $httptestids)
);
while ($row = DBfetch($result)) {
$db_httptests[$row['httptestid']]['items'][$row['itemid']]['tags'][$row['itemtagid']] =
array_diff_key($row, array_flip(['httptestid', 'itemid']));
}
}
/**
* @param array $httptests
* @param array $db_httptests
*/
private static function addAffectedFields(array $httptests, array &$db_httptests): void {
$httptestids = [];
$types = [];
foreach ($httptests as $httptest) {
if (array_key_exists('headers', $httptest)) {
$httptestids[$httptest['httptestid']] = true;
$types[] = ZBX_HTTPFIELD_HEADER;
$db_httptests[$httptest['httptestid']]['headers'] = [];
}
if (array_key_exists('variables', $httptest)) {
$httptestids[$httptest['httptestid']] = true;
$types[] = ZBX_HTTPFIELD_VARIABLE;
$db_httptests[$httptest['httptestid']]['variables'] = [];
}
}
if (!$httptestids) {
return;
}
$options = [
'output' => ['httptest_fieldid', 'httptestid', 'type', 'name', 'value'],
'filter' => [
'httptestid' => array_keys($httptestids),
'type' => $types
]
];
$result = DBselect(DB::makeSql('httptest_field', $options));
while ($row = DBfetch($result)) {
$field_name = ($row['type'] == ZBX_HTTPFIELD_HEADER) ? 'headers' : 'variables';
if (array_key_exists($field_name, $db_httptests[$row['httptestid']])) {
$db_httptests[$row['httptestid']][$field_name][$row['httptest_fieldid']] =
array_diff_key($row, array_flip(['httptestid']));
}
}
}
/**
* @param array $httptests
* @param array $db_httptests
*/
private static function addAffectedSteps(array $httptests, array &$db_httptests): void {
$httptestids = [];
foreach ($httptests as $httptest) {
$name_updated = $httptest['name'] != $db_httptests[$httptest['httptestid']]['name'];
if (array_key_exists('steps', $httptest) || $name_updated) {
$httptestids[] = $httptest['httptestid'];
$db_httptests[$httptest['httptestid']]['steps'] = [];
}
}
if ($httptestids) {
$options = [
'output' => ['httpstepid', 'httptestid', 'name', 'no', 'url', 'timeout', 'posts', 'required',
'status_codes','follow_redirects', 'retrieve_mode', 'post_type'
],
'filter' => ['httptestid' => $httptestids]
];
$result = DBselect(DB::makeSql('httpstep', $options));
while ($row = DBfetch($result)) {
$db_httptests[$row['httptestid']]['steps'][$row['httpstepid']] =
array_diff_key($row, array_flip(['httptestid']));
}
}
self::addAffectedStepItems($httptests, $db_httptests);
self::addAffectedStepFields($httptests, $db_httptests);
}
/**
* @param array $httptests
* @param array $db_httptests
*/
private static function addAffectedStepItems(array $httptests, array &$db_httptests): void {
$httptestids = [];
foreach ($httptests as $httptest) {
$db_httptest = $db_httptests[$httptest['httptestid']];
$name_updated = $httptest['name'] != $db_httptest['name'];
$status_updated = array_key_exists('status', $httptest) && $httptest['status'] != $db_httptest['status'];
$delay_updated = array_key_exists('delay', $httptest) && $httptest['delay'] != $db_httptest['delay'];
$templateid_updated = array_key_exists('templateid', $httptest)
&& bccomp($httptest['templateid'], $db_httptest['templateid']) != 0;
if (array_key_exists('steps', $httptest) || $name_updated || $status_updated || $delay_updated
|| $templateid_updated || array_key_exists('tags', $httptest)) {
$httptestids[] = $httptest['httptestid'];
}
}
if (!$httptestids) {
return;
}
$result = DBselect(
'SELECT hs.httptestid,hs.httpstepid,hsi.type AS test_type,hsi.itemid,i.name,i.key_,i.status,i.delay,'.
'i.templateid'.
' FROM httpstep hs,httpstepitem hsi,items i'.
' WHERE hs.httpstepid=hsi.httpstepid'.
' AND hsi.itemid=i.itemid'.
' AND '.dbConditionId('hs.httptestid', $httptestids)
);
while ($row = DBfetch($result)) {
$db_httptests[$row['httptestid']]['steps'][$row['httpstepid']]['items'][$row['itemid']] =
array_diff_key($row, array_flip(['httptestid', 'httpstepid']));
}
self::addAffectedStepItemTags($httptests, $db_httptests);
}
/**
* @param array $httptests
* @param array $db_httptests
*/
private static function addAffectedStepItemTags(array $httptests, array &$db_httptests): void {
$httptestids = [];
foreach ($httptests as $httptest) {
if (!array_key_exists('tags', $httptest)) {
continue;
}
$httptestids[] = $httptest['httptestid'];
foreach ($db_httptests[$httptest['httptestid']]['steps'] as &$db_step) {
if (!array_key_exists('items', $db_step)) {
continue;
}
foreach ($db_step['items'] as &$db_item) {
$db_item['tags'] = [];
}
unset($db_item);
}
unset($db_step);
}
if (!$httptestids) {
return;
}
$result = DBselect(
'SELECT hs.httptestid,hs.httpstepid,hsi.itemid,it.itemtagid,it.tag,it.value'.
' FROM httpstep hs,httpstepitem hsi,item_tag it'.
' WHERE hs.httpstepid=hsi.httpstepid'.
' AND hsi.itemid=it.itemid'.
' AND '.dbConditionId('hs.httptestid', $httptestids)
);
while ($row = DBfetch($result)) {
$db_httptests[$row['httptestid']]['steps'][$row['httpstepid']]['items'][$row['itemid']]['tags'][$row['itemtagid']] =
array_diff_key($row, array_flip(['httptestid', 'httpstepid', 'itemid']));
}
}
/**
* @param array $httptests
* @param array $db_httptests
*/
private static function addAffectedStepFields(array $httptests, array &$db_httptests): void {
$httpstepids = [];
$types = [];
$field_names = [
ZBX_HTTPFIELD_HEADER => 'headers',
ZBX_HTTPFIELD_VARIABLE => 'variables',
ZBX_HTTPFIELD_POST_FIELD => 'posts',
ZBX_HTTPFIELD_QUERY_FIELD => 'query_fields'
];
foreach ($httptests as $httptest) {
if (!array_key_exists('steps', $httptest)) {
continue;
}
foreach ($httptest['steps'] as $step) {
if (!array_key_exists('httpstepid', $step)
|| !array_key_exists($step['httpstepid'], $db_httptests[$httptest['httptestid']]['steps'])) {
continue;
}
$db_step = &$db_httptests[$httptest['httptestid']]['steps'][$step['httpstepid']];
if (array_key_exists('headers', $step)) {
$httpstepids[$step['httpstepid']] = true;
$types[ZBX_HTTPFIELD_HEADER] = true;
$db_step['headers'] = [];
}
if (array_key_exists('variables', $step)) {
$httpstepids[$step['httpstepid']] = true;
$types[ZBX_HTTPFIELD_VARIABLE] = true;
$db_step['variables'] = [];
}
if (array_key_exists('posts', $step) && $db_step['post_type'] == ZBX_POSTTYPE_FORM) {
$httpstepids[$step['httpstepid']] = true;
$types[ZBX_HTTPFIELD_POST_FIELD] = true;
$db_step['posts'] = [];
}
if (array_key_exists('query_fields', $step)) {
$httpstepids[$step['httpstepid']] = true;
$types[ZBX_HTTPFIELD_QUERY_FIELD] = true;
$db_step['query_fields'] = [];
}
}
}
unset($db_step);
if (!$httpstepids) {
return;
}
$result = DBselect(
'SELECT hs.httptestid,hs.httpstepid,hsf.httpstep_fieldid,hsf.type,hsf.name,hsf.value'.
' FROM httpstep hs,httpstep_field hsf'.
' WHERE hs.httpstepid=hsf.httpstepid'.
' AND '.dbConditionId('hs.httpstepid', array_keys($httpstepids)).
' AND '.dbConditionInt('hsf.type', array_keys($types))
);
while ($row = DBfetch($result)) {
$field_name = $field_names[$row['type']];
$db_step = &$db_httptests[$row['httptestid']]['steps'][$row['httpstepid']];
if (array_key_exists($field_name, $db_step)) {
$db_step[$field_name][$row['httpstep_fieldid']] = [
'httpstep_fieldid' => $row['httpstep_fieldid'],
'name' => $row['name'],
'value' => $row['value']
];
}
}
unset($db_step);
}
/**
* @param array $httptests
* @param array $db_httptests
*/
private static function addAffectedTags(array $httptests, array &$db_httptests): void {
$httptestids = [];
foreach ($httptests as $httptest) {
$steps_to_create_exists = array_key_exists('steps', $httptest)
&& count($httptest['steps']) > count(array_column($httptest['steps'], 'httpstepid'));
if (array_key_exists('tags', $httptest) || $steps_to_create_exists) {
$httptestids[] = $httptest['httptestid'];
$db_httptests[$httptest['httptestid']]['tags'] = [];
}
}
if (!$httptestids) {
return;
}
$options = [
'output' => ['httptesttagid', 'httptestid', 'tag', 'value'],
'filter' => ['httptestid' => $httptestids]
];
$result = DBselect(DB::makeSql('httptest_tag', $options));
while ($row = DBfetch($result)) {
$db_httptests[$row['httptestid']]['tags'][$row['httptesttagid']] =
array_diff_key($row, array_flip(['httptestid']));
}
}
/**
* @param array $httptests
*/
private static function createItems(array $httptests): void {
$items = [];
$type_items = [
HTTPSTEP_ITEM_TYPE_IN => [
'value_type' => ITEM_VALUE_TYPE_FLOAT,
'units' => 'Bps'
],
HTTPSTEP_ITEM_TYPE_LASTSTEP => [
'value_type' => ITEM_VALUE_TYPE_UINT64,
'units' => ''
],
HTTPSTEP_ITEM_TYPE_LASTERROR => [
'value_type' => ITEM_VALUE_TYPE_STR,
'units' => ''
]
];
foreach ($httptests as $httptest) {
if (!array_key_exists('status', $httptest)) {
$httptest['status'] = DB::getDefault('httptest', 'status');
}
$item_status = $httptest['status'] == HTTPTEST_STATUS_ACTIVE ? ITEM_STATUS_ACTIVE : ITEM_STATUS_DISABLED;
$item_tags = array_key_exists('tags', $httptest) ? $httptest['tags'] : [];
if (!array_key_exists('delay', $httptest)) {
$httptest['delay'] = DB::getDefault('httptest', 'delay');
}
foreach ($type_items as $type => $type_item) {
$item_key = self::getTestKey($type, $httptest['name']);
$items[] = [
'host_status' => $httptest['host_status'],
'flags' => ZBX_FLAG_DISCOVERY_NORMAL,
'hostid' => $httptest['hostid'],
'name' => self::getTestName($type, $httptest['name']),
'type' => ITEM_TYPE_HTTPTEST,
'key_' => $item_key,
'history' => self::ITEM_HISTORY,
'trends' => self::ITEM_TRENDS,
'status' => $item_status,
'tags' => $item_tags,
'delay' => $httptest['delay'],
'templateid' => array_key_exists('templateid', $httptest)
? self::$parent_itemids[$httptest['templateid']][$item_key]
: 0
] + $type_item;
}
}
CItem::createForce($items);
$itemids = array_column($items, 'itemid');
$ins_httptestitems = [];
foreach ($httptests as $httptest) {
foreach ($type_items as $type => $foo) {
$ins_httptestitems[] = [
'httptestid' => $httptest['httptestid'],
'itemid' => array_shift($itemids),
'type' => $type
];
}
}
DB::insertBatch('httptestitem', $ins_httptestitems);
}
/**
* @param array $httptests
* @param array $db_httptests
*/
private static function updateItems(array $httptests, array $db_httptests): void {
$items = [];
$db_items = [];
foreach ($httptests as $httptest) {
if (!array_key_exists('items', $db_httptests[$httptest['httptestid']])) {
continue;
}
$db_httptest = $db_httptests[$httptest['httptestid']];
$db_items += $db_httptest['items'];
foreach ($db_httptest['items'] as $db_item) {
$item = [];
if ($httptest['name'] != $db_httptest['name']) {
$item += [
'name' => self::getTestName($db_item['test_type'], $httptest['name']),
'key_' => self::getTestKey($db_item['test_type'], $httptest['name'])
];
}
if (array_key_exists('status', $httptest) && $httptest['status'] != $db_httptest['status']) {
$item['status'] = $httptest['status'] == HTTPTEST_STATUS_ACTIVE
? ITEM_STATUS_ACTIVE
: ITEM_STATUS_DISABLED;
}
if (array_key_exists('delay', $httptest) && $httptest['delay'] !== $db_httptest['delay']) {
$item['delay'] = $httptest['delay'];
}
if (array_key_exists('templateid', $httptest)
&& bccomp($httptest['templateid'], $db_httptest['templateid']) != 0) {
$item_key = array_key_exists('key_', $item) ? $item['key_'] : $db_item['key_'];
$item['templateid'] = $httptest['templateid'] == 0
? 0
: self::$parent_itemids[$httptest['templateid']][$item_key];
}
if (array_key_exists('tags', $httptest)) {
$item['tags'] = $httptest['tags'];
}
$items[] = ['itemid' => $db_item['itemid']] + $item;
}
if (array_key_exists('steps', $httptest)) {
continue;
}
foreach ($db_httptest['steps'] as $db_step) {
$db_items += $db_step['items'];
foreach ($db_step['items'] as $db_item) {
$item = [];
if ($httptest['name'] != $db_httptest['name']) {
$item += [
'name' => self::getStepName($db_item['test_type'], $httptest['name'], $db_step['name']),
'key_' => self::getStepKey($db_item['test_type'], $httptest['name'], $db_step['name'])
];
}
if (array_key_exists('status', $httptest) && $httptest['status'] != $db_httptest['status']) {
$item['status'] = $httptest['status'] == HTTPTEST_STATUS_ACTIVE
? ITEM_STATUS_ACTIVE
: ITEM_STATUS_DISABLED;
}
if (array_key_exists('delay', $httptest) && $httptest['delay'] !== $db_httptest['delay']) {
$item['delay'] = $httptest['delay'];
}
if (array_key_exists('templateid', $httptest)
&& bccomp($httptest['templateid'], $db_httptest['templateid']) != 0) {
$item_key = array_key_exists('key_', $item) ? $item['key_'] : $db_item['key_'];
$item['templateid'] = $httptest['templateid'] == 0
? 0
: self::$parent_itemids[$httptest['templateid']][$item_key];
}
if (array_key_exists('tags', $httptest)) {
$item['tags'] = $httptest['tags'];
}
$items[] = ['itemid' => $db_item['itemid']] + $item;
}
}
}
if ($items) {
CItem::updateForce($items, $db_items);
}
}
/**
* @param array $httptests
* @param array|null $db_httptests
*/
private static function updateFields(array &$httptests, array $db_httptests = null): void {
$ins_fields = [];
$upd_fields = [];
$del_fieldids = [];
foreach ($httptests as &$httptest) {
if (array_key_exists('headers', $httptest)) {
$db_headers = $db_httptests !== null ? $db_httptests[$httptest['httptestid']]['headers'] : [];
foreach ($httptest['headers'] as &$header) {
$db_fieldid = key(array_filter($db_headers,
static function (array $db_header) use ($header): bool {
return $header['name'] == $db_header['name'] && $header['value'] == $db_header['value'];
}
));
if ($db_fieldid !== null) {
$header['httptest_fieldid'] = $db_fieldid;
unset($db_headers[$db_fieldid]);
}
else {
$ins_fields[] = [
'httptestid' => $httptest['httptestid'],
'type' => ZBX_HTTPFIELD_HEADER
] + $header;
}
}
unset($header);
$del_fieldids = array_merge($del_fieldids, array_keys($db_headers));
}
if (array_key_exists('variables', $httptest)) {
$db_variables = $db_httptests !== null
? array_column($db_httptests[$httptest['httptestid']]['variables'], null, 'name')
: [];
foreach ($httptest['variables'] as &$variable) {
if (array_key_exists($variable['name'], $db_variables)) {
$db_variable = $db_variables[$variable['name']];
$upd_variable = DB::getUpdatedValues('httptest_field', $variable, $db_variable);
if ($upd_variable) {
$upd_fields[] = [
'values' => $upd_variable,
'where' => ['httptest_fieldid' => $db_variable['httptest_fieldid']]
];
}
$variable['httptest_fieldid'] = $db_variable['httptest_fieldid'];
unset($db_variables[$variable['name']]);
}
else {
$ins_fields[] = [
'httptestid' => $httptest['httptestid'],
'type' => ZBX_HTTPFIELD_VARIABLE
] + $variable;
}
}
unset($variable);
$del_fieldids = array_merge($del_fieldids, array_column($db_variables, 'httptest_fieldid'));
}
}
unset($httptest);
if ($del_fieldids) {
DB::delete('httptest_field', ['httptest_fieldid' => $del_fieldids]);
}
if ($upd_fields) {
DB::update('httptest_field', $upd_fields);
}
if ($ins_fields) {
DB::insertBatch('httptest_field', $ins_fields);
}
}
/**
* @param array $httptests
* @param array|null $db_httptests
*/
private static function updateSteps(array &$httptests, array $db_httptests = null): void {
$ins_steps = [];
$upd_steps = [];
$update_step_items = false;
$del_stepids = [];
$del_db_items = [];
foreach ($httptests as $httptest) {
if (!array_key_exists('steps', $httptest)) {
continue;
}
$db_steps = $db_httptests !== null ? $db_httptests[$httptest['httptestid']]['steps'] : [];
foreach ($httptest['steps'] as $step) {
if (array_key_exists('httpstepid', $step)) {
if (array_key_exists('posts', $step)) {
if (is_array($step['posts'])) {
if ($db_steps[$step['httpstepid']]['post_type'] == ZBX_POSTTYPE_RAW) {
if ($step['posts']) {
$step['post_type'] = ZBX_POSTTYPE_FORM;
}
$step['posts'] = '';
}
else {
if (!$step['posts']) {
$step['post_type'] = ZBX_POSTTYPE_RAW;
}
unset($step['posts']);
}
}
else {
if ($db_steps[$step['httpstepid']]['post_type'] == ZBX_POSTTYPE_FORM) {
$step['post_type'] = ZBX_POSTTYPE_RAW;
$db_steps[$step['httpstepid']]['posts'] = '';
}
}
}
$upd_step = DB::getUpdatedValues('httpstep', $step, $db_steps[$step['httpstepid']]);
if ($upd_step) {
$upd_steps[] = [
'values' => $upd_step,
'where' => ['httpstepid' => $step['httpstepid']]
];
}
if (array_key_exists('items', $db_steps[$step['httpstepid']])) {
$update_step_items = true;
}
unset($db_steps[$step['httpstepid']]);
}
else {
if (array_key_exists('posts', $step) && is_array($step['posts'])) {
$step['post_type'] = ZBX_POSTTYPE_FORM;
unset($step['posts']);
}
$ins_steps[] = ['httptestid' => $httptest['httptestid']] + $step;
}
}
$del_stepids = array_merge($del_stepids, array_keys($db_steps));
foreach ($db_steps as $db_step) {
if (!array_key_exists('items', $db_step)) {
continue;
}
foreach ($db_step['items'] as $db_item) {
$del_db_items[$db_item['itemid']] = $db_item;
}
}
}
if ($del_stepids) {
if ($del_db_items) {
CItem::addInheritedItems($del_db_items);
DB::delete('httpstepitem', ['itemid' => array_keys($del_db_items)]);
CItem::deleteForce($del_db_items);
}
DB::delete('httpstep_field', ['httpstepid' => $del_stepids]);
DB::delete('httpstep', ['httpstepid' => $del_stepids]);
}
if ($upd_steps) {
DB::update('httpstep', $upd_steps);
}
if ($update_step_items) {
self::updateStepItems($httptests, $db_httptests);
}
if ($ins_steps) {
$stepids = DB::insert('httpstep', $ins_steps);
foreach ($httptests as &$httptest) {
if (!array_key_exists('steps', $httptest)) {
continue;
}
foreach ($httptest['steps'] as &$step) {
if (!array_key_exists('httpstepid', $step)) {
$step['httpstepid'] = current($stepids);
next($stepids);
}
}
unset($step);
}
unset($httptest);
self::createStepItems($httptests, $stepids, $db_httptests);
}
self::updateStepFields($httptests, $db_httptests);
}
/**
* @param array $httptests
* @param array $db_httptests
*/
private static function updateStepItems(array $httptests, array $db_httptests): void {
$items = [];
$db_items = [];
foreach ($httptests as $httptest) {
if (!array_key_exists('steps', $httptest)) {
continue;
}
$db_httptest = $db_httptests[$httptest['httptestid']];
foreach ($httptest['steps'] as $step) {
if (!array_key_exists('httpstepid', $step)
|| !array_key_exists('items', $db_httptest['steps'][$step['httpstepid']])) {
continue;
}
$db_step = $db_httptest['steps'][$step['httpstepid']];
if (!array_key_exists('name', $step)) {
$step['name'] = $db_step['name'];
}
$db_items += $db_step['items'];
foreach ($db_step['items'] as $db_item) {
$item = [];
if ($httptest['name'] != $db_httptest['name'] || $step['name'] !== $db_step['name']) {
$item += [
'name' => self::getStepName($db_item['test_type'], $httptest['name'], $step['name']),
'key_' => self::getStepKey($db_item['test_type'], $httptest['name'], $step['name'])
];
}
if (array_key_exists('status', $httptest) && $httptest['status'] != $db_httptest['status']) {
$item['status'] = $httptest['status'] == HTTPTEST_STATUS_ACTIVE
? ITEM_STATUS_ACTIVE
: ITEM_STATUS_DISABLED;
}
if (array_key_exists('delay', $httptest) && $httptest['delay'] !== $db_httptest['delay']) {
$item['delay'] = $httptest['delay'];
}
if (array_key_exists('tags', $httptest)) {
$item['tags'] = $httptest['tags'];
}
$items[] = ['itemid' => $db_item['itemid']] + $item;
}
}
}
if ($items) {
CItem::updateForce($items, $db_items);
}
}
/**
* @param array $httptests
* @param array $stepids
* @param array|null $db_httptests
*/
private static function createStepItems(array $httptests, array $stepids, ?array $db_httptests): void {
$items = [];
$type_items = [
HTTPSTEP_ITEM_TYPE_RSPCODE => [
'value_type' => ITEM_VALUE_TYPE_UINT64,
'units' => ''
],
HTTPSTEP_ITEM_TYPE_TIME => [
'value_type' => ITEM_VALUE_TYPE_FLOAT,
'units' => 's'
],
HTTPSTEP_ITEM_TYPE_IN => [
'value_type' => ITEM_VALUE_TYPE_FLOAT,
'units' => 'Bps'
]
];
foreach ($httptests as $httptest) {
if (!array_key_exists('steps', $httptest)) {
continue;
}
if ($db_httptests !== null) {
$httptest['host_status'] = $db_httptests[$httptest['httptestid']]['host_status'];
}
if (!array_key_exists('status', $httptest)) {
$httptest['status'] = ($db_httptests !== null)
? $db_httptests[$httptest['httptestid']]['status']
: DB::getDefault('httptest', 'status');
}
$item_status = $httptest['status'] == HTTPTEST_STATUS_ACTIVE ? ITEM_STATUS_ACTIVE : ITEM_STATUS_DISABLED;
$item_tags = [];
if (array_key_exists('tags', $httptest)) {
$item_tags = $httptest['tags'];
}
elseif ($db_httptests !== null) {
foreach ($db_httptests[$httptest['httptestid']]['tags'] as $tag) {
$item_tags[] = array_intersect_key($tag, array_flip(['tag', 'value']));
}
}
if (!array_key_exists('delay', $httptest)) {
$httptest['delay'] = ($db_httptests !== null)
? $db_httptests[$httptest['httptestid']]['delay']
: DB::getDefault('httptest', 'delay');
}
foreach ($httptest['steps'] as $step) {
if (!in_array($step['httpstepid'], $stepids)) {
continue;
}
foreach ($type_items as $type => $type_item) {
$item_key = self::getStepKey($type, $httptest['name'], $step['name']);
$items[] = [
'host_status' => $httptest['host_status'],
'flags' => ZBX_FLAG_DISCOVERY_NORMAL,
'hostid' => $httptest['hostid'],
'name' => self::getStepName($type, $httptest['name'], $step['name']),
'type' => ITEM_TYPE_HTTPTEST,
'key_' => $item_key,
'history' => self::ITEM_HISTORY,
'trends' => self::ITEM_TRENDS,
'status' => $item_status,
'tags' => $item_tags,
'delay' => $httptest['delay'],
'templateid' => array_key_exists('templateid', $httptest)
? self::$parent_itemids[$httptest['templateid']][$item_key]
: 0
] + $type_item;
}
}
}
CItem::createForce($items);
$itemids = array_column($items, 'itemid');
$ins_httpstepitems = [];
foreach ($httptests as $httptest) {
if (!array_key_exists('steps', $httptest)) {
continue;
}
foreach ($httptest['steps'] as $step) {
if (!in_array($step['httpstepid'], $stepids)) {
continue;
}
foreach ($type_items as $type => $foo) {
$ins_httpstepitems[] = [
'httpstepid' => $step['httpstepid'],
'itemid' => array_shift($itemids),
'type' => $type
];
}
}
}
DB::insertBatch('httpstepitem', $ins_httpstepitems);
}
/**
* @param array $httptests
* @param array|null $db_httptests
*/
private static function updateStepFields(array &$httptests, ?array $db_httptests): void {
$ins_fields = [];
$upd_fields = [];
$del_fieldids = [];
foreach ($httptests as &$httptest) {
if (!array_key_exists('steps', $httptest)) {
continue;
}
$db_httptest = $db_httptests !== null ? $db_httptests[$httptest['httptestid']] : null;
foreach ($httptest['steps'] as &$step) {
$db_step = ($db_httptest !== null && array_key_exists($step['httpstepid'], $db_httptest['steps']))
? $db_httptest['steps'][$step['httpstepid']]
: null;
if (array_key_exists('headers', $step)) {
$db_headers = $db_step !== null ? $db_step['headers'] : [];
foreach ($step['headers'] as &$header) {
$db_fieldid = key(array_filter($db_headers,
static function (array $db_header) use ($header): bool {
return $header['name'] == $db_header['name'] && $header['value'] == $db_header['value'];
}
));
if ($db_fieldid !== null) {
$header['httpstep_fieldid'] = $db_fieldid;
unset($db_headers[$db_fieldid]);
}
else {
$ins_fields[] = [
'httpstepid' => $step['httpstepid'],
'type' => ZBX_HTTPFIELD_HEADER
] + $header;
}
}
unset($header);
$del_fieldids = array_merge($del_fieldids, array_keys($db_headers));
}
if (array_key_exists('variables', $step)) {
$db_variables = $db_step !== null ? array_column($db_step['variables'], null, 'name') : [];
foreach ($step['variables'] as &$variable) {
if (array_key_exists($variable['name'], $db_variables)) {
$db_variable = $db_variables[$variable['name']];
$upd_variable = DB::getUpdatedValues('httpstep_field', $variable, $db_variable);
if ($upd_variable) {
$upd_fields[] = [
'values' => $upd_variable,
'where' => ['httpstep_fieldid' => $db_variable['httpstep_fieldid']]
];
}
$variable['httpstep_fieldid'] = $db_variable['httpstep_fieldid'];
unset($db_variables[$variable['name']]);
}
else {
$ins_fields[] = [
'httpstepid' => $step['httpstepid'],
'type' => ZBX_HTTPFIELD_VARIABLE
] + $variable;
}
}
unset($variable);
$del_fieldids = array_merge($del_fieldids, array_column($db_variables, 'httpstep_fieldid'));
}
if (array_key_exists('posts', $step)) {
if (is_array($step['posts'])) {
$db_posts = $db_step !== null && is_array($db_step['posts']) ? $db_step['posts'] : [];
foreach ($step['posts'] as &$post) {
$db_fieldid = key(array_filter($db_posts,
static function (array $db_post) use ($post): bool {
return $post['name'] == $db_post['name'] && $post['value'] == $db_post['value'];
}
));
if ($db_fieldid !== null) {
$post['httpstep_fieldid'] = $db_fieldid;
unset($db_posts[$db_fieldid]);
}
else {
$ins_fields[] = [
'httpstepid' => $step['httpstepid'],
'type' => ZBX_HTTPFIELD_POST_FIELD
] + $post;
}
}
unset($post);
$del_fieldids = array_merge($del_fieldids, array_keys($db_posts));
}
elseif ($db_step !== null && is_array($db_step['posts'])) {
$del_fieldids = array_merge($del_fieldids, array_keys($db_step['posts']));
}
}
if (array_key_exists('query_fields', $step)) {
$db_query_fields = $db_step !== null ? $db_step['query_fields'] : [];
foreach ($step['query_fields'] as &$query_field) {
$db_fieldid = key(array_filter($db_query_fields,
static function (array $db_query_field) use ($query_field): bool {
return $query_field['name'] == $db_query_field['name']
&& $query_field['value'] == $db_query_field['value'];
}
));
if ($db_fieldid !== null) {
$query_field['httpstep_fieldid'] = $db_fieldid;
unset($db_query_fields[$db_fieldid]);
}
else {
$ins_fields[] = [
'httpstepid' => $step['httpstepid'],
'type' => ZBX_HTTPFIELD_QUERY_FIELD
] + $query_field;
}
}
unset($query_field);
$del_fieldids = array_merge($del_fieldids, array_keys($db_query_fields));
}
}
unset($step);
}
unset($httptest);
if ($del_fieldids) {
DB::delete('httpstep_field', ['httpstep_fieldid' => $del_fieldids]);
}
if ($upd_fields) {
DB::update('httpstep_field', $upd_fields);
}
if ($ins_fields) {
DB::insertBatch('httpstep_field', $ins_fields);
}
}
/**
* @param array $httptests
* @param array|null $db_httptests
*/
private static function updateTags(array &$httptests, array $db_httptests = null): void {
$ins_tags = [];
$del_tagids = [];
foreach ($httptests as &$httptest) {
if (!array_key_exists('tags', $httptest)) {
continue;
}
$db_tags = $db_httptests !== null ? $db_httptests[$httptest['httptestid']]['tags'] : [];
foreach ($httptest['tags'] as &$tag) {
$db_tagid = key(array_filter($db_tags, static function (array $db_tag) use ($tag): bool {
return $tag['tag'] == $db_tag['tag']
&& (!array_key_exists('value', $tag) || $tag['value'] == $db_tag['value']);
}));
if ($db_tagid !== null) {
$tag['httptesttagid'] = $db_tagid;
unset($db_tags[$db_tagid]);
}
else {
$ins_tags[] = ['httptestid' => $httptest['httptestid']] + $tag;
}
}
unset($tag);
$del_tagids = array_merge($del_tagids, array_keys($db_tags));
}
unset($httptest);
if ($del_tagids) {
DB::delete('httptest_tag', ['httptesttagid' => $del_tagids]);
}
if ($ins_tags) {
DB::insert('httptest_tag', $ins_tags);
}
}
/**
* Link http tests in template to hosts.
*
* @param $templateId
* @param $hostIds
*/
public function link($templateId, $hostIds) {
$hostIds = zbx_toArray($hostIds);
$httpTests = API::HttpTest()->get([
'output' => ['httptestid', 'name', 'delay', 'status', 'agent', 'authentication',
'http_user', 'http_password', 'hostid', 'templateid', 'http_proxy', 'retries', 'ssl_cert_file',
'ssl_key_file', 'ssl_key_password', 'verify_peer', 'verify_host', 'variables', 'headers'
],
'hostids' => $templateId,
'selectSteps' => ['httpstepid', 'name', 'no', 'url', 'timeout', 'posts', 'required', 'status_codes',
'follow_redirects', 'retrieve_mode', 'variables', 'headers', 'query_fields'
],
'selectTags' => ['tag', 'value'],
'preservekeys' => true,
'nopermissions' => true
]);
$this->inherit($httpTests, $hostIds);
}
/**
* Inherit passed http tests to hosts.
* If $hostids is empty that means that we need to inherit all $httptests to hosts which are linked to templates
* where $httptests belong.
*
* @param array $httptests
* @param array $hostIds
*
* @return bool
*/
public function inherit(array $httptests, array $hostids = []) {
$template_hosts = $this->getTemplateHosts($httptests, $hostids);
if (!$template_hosts) {
return true;
}
foreach ($httptests as $i => $httptest) {
if (!array_key_exists($httptest['hostid'], $template_hosts)) {
unset($httptests[$i]);
}
}
self::$parent_itemids = self::getItemIds($httptests);
$preparedHttpTests = $this->prepareInheritedHttpTests($httptests, $template_hosts);
$inheritedHttpTests = $this->save($preparedHttpTests);
$this->inherit($inheritedHttpTests);
return true;
}
/**
* Get hosts to which is necessary to inherit the given web scenarios indexed by template ID.
*
* @param array $httptests
* @param array $hostids
*
* @return array
*/
private static function getTemplateHosts(array $httptests, array $hostids): array {
$template_hosts = [];
$hostids_condition = $hostids ? ' AND '.dbConditionId('ht.hostid', $hostids) : '';
$result = DBselect(
'SELECT ht.templateid,ht.hostid,h.status'.
' FROM hosts_templates ht,hosts h'.
' WHERE ht.hostid=h.hostid'.
' AND '.dbConditionId('ht.templateid', array_column($httptests, 'hostid')).
$hostids_condition
);
while ($row = DBfetch($result)) {
$template_hosts[$row['templateid']][$row['hostid']] = array_diff_key($row, array_flip(['templateid']));
}
return $template_hosts;
}
/**
* Get item IDs array of the given web scenarios and their steps indexed by httptest ID and item key.
*
* @param array $httptests
*
* @return array
*/
private static function getItemIds(array $httptests): array {
$httptest_itemids = [];
$httptestids = array_column($httptests, 'httptestid');
$result = DBselect(
'SELECT hti.httptestid,hti.itemid,i.key_'.
' FROM httptestitem hti,items i'.
' WHERE hti.itemid=i.itemid'.
' AND '.dbConditionId('hti.httptestid', $httptestids)
);
while ($row = DBfetch($result)) {
$httptest_itemids[$row['httptestid']][$row['key_']] = $row['itemid'];
}
$result = DBselect(
'SELECT hs.httptestid,hsi.itemid,i.key_'.
' FROM httpstep hs,httpstepitem hsi,items i'.
' WHERE hs.httpstepid=hsi.httpstepid'.
' AND hsi.itemid=i.itemid'.
' AND '.dbConditionId('hs.httptestid', $httptestids)
);
while ($row = DBfetch($result)) {
$httptest_itemids[$row['httptestid']][$row['key_']] = $row['itemid'];
}
return $httptest_itemids;
}
/**
* Generate http tests data for inheritance.
* Using passed parameters decide if new http tests must be created on host or existing ones must be updated.
*
* @param array $httpTests which we need to inherit
* @param array $template_hosts
*
* @throws Exception
* @return array with http tests, existing apps have 'httptestid' key.
*/
protected function prepareInheritedHttpTests(array $httpTests, array $template_hosts) {
$hostHttpTests = $this->getHostHttpTests($template_hosts);
$result = [];
foreach ($httpTests as $httpTest) {
$httpTestId = $httpTest['httptestid'];
foreach ($hostHttpTests as $hostId => $hostHttpTest) {
// if http test template is not linked to host we skip it
if (!array_key_exists($hostId, $template_hosts[$httpTest['hostid']])) {
continue;
}
$exHttpTest = null;
// update by templateid
if (isset($hostHttpTest['byTemplateId'][$httpTestId])) {
$exHttpTest = $hostHttpTest['byTemplateId'][$httpTestId];
/*
* 'templateid' needs to be checked here too in case we update linked httptest to name
* that already exists on a linked host.
*/
if (isset($httpTest['name']) && isset($hostHttpTest['byName'][$httpTest['name']])
&& !idcmp($exHttpTest['templateid'], $hostHttpTest['byName'][$httpTest['name']]['templateid'])) {
$host = DBfetch(DBselect('SELECT h.name FROM hosts h WHERE h.hostid='.zbx_dbstr($hostId)));
throw new Exception(
_s('Web scenario "%1$s" already exists on host "%2$s".', $exHttpTest['name'], $host['name'])
);
}
}
// update by name
elseif (isset($hostHttpTest['byName'][$httpTest['name']])) {
$exHttpTest = $hostHttpTest['byName'][$httpTest['name']];
if (bccomp($exHttpTest['templateid'], $httpTestId) == 0
|| $exHttpTest['templateid'] != 0
|| !$this->compareHttpSteps($httpTest, $exHttpTest)) {
$host = DBfetch(DBselect('SELECT h.name FROM hosts h WHERE h.hostid='.zbx_dbstr($hostId)));
throw new Exception(
_s('Web scenario "%1$s" already exists on host "%2$s".', $exHttpTest['name'], $host['name'])
);
}
}
$newHttpTest = $httpTest;
$newHttpTest['uuid'] = '';
$newHttpTest['hostid'] = $hostId;
$newHttpTest['templateid'] = $httpTestId;
if ($exHttpTest) {
$newHttpTest['httptestid'] = $exHttpTest['httptestid'];
if (array_key_exists('variables', $newHttpTest)) {
foreach ($newHttpTest['variables'] as &$variable) {
unset($variable['httptest_fieldid']);
}
unset($variable);
}
if (isset($hostHttpTest['byTemplateId'][$httpTestId])) {
$this->setHttpTestParent($exHttpTest['httptestid'], $httpTestId);
if (isset($newHttpTest['steps'])) {
$newHttpTest['steps'] = $this->prepareHttpSteps($httpTest['steps'],
$exHttpTest['httptestid']
);
}
}
elseif (isset($hostHttpTest['byName'][$httpTest['name']])) {
unset($newHttpTest['steps']);
}
}
else {
unset($newHttpTest['httptestid']);
$newHttpTest['host_status'] = $template_hosts[$httpTest['hostid']][$hostId]['status'];
foreach ($newHttpTest['steps'] as &$step) {
unset($step['httpstepid']);
}
unset($step);
}
$result[] = $newHttpTest;
}
}
return $result;
}
/**
* Find and set first parent id for http test.
*
* @param $id
* @param $parentId
*/
protected function setHttpTestParent($id, $parentId) {
while (isset($this->httpTestParents[$parentId])) {
$parentId = $this->httpTestParents[$parentId];
}
$this->httpTestParents[$id] = $parentId;
}
/**
* Get hosts http tests for each passed hosts.
* Each host has two hashes with http tests, one with name keys other with templateid keys.
*
* Resulting structure is:
* array(
* 'hostid1' => array(
* 'byName' => array(ht1data, ht2data, ...),
* 'nyTemplateId' => array(ht1data, ht2data, ...)
* ), ...
* );
*
* @param array $template_hosts
*
* @return array
*/
protected function getHostHttpTests(array $template_hosts) {
$hostHttpTests = [];
foreach ($template_hosts as $hosts) {
foreach ($hosts as $hostid => $foo) {
$hostHttpTests[$hostid] = ['byName' => [], 'byTemplateId' => []];
}
}
$dbCursor = DBselect(
'SELECT ht.httptestid,ht.name,ht.delay,ht.agent,ht.hostid,ht.templateid,ht.http_proxy,ht.retries'.
' FROM httptest ht'.
' WHERE '.dbConditionId('ht.hostid', array_keys($hostHttpTests))
);
while ($dbHttpTest = DBfetch($dbCursor)) {
$hostHttpTests[$dbHttpTest['hostid']]['byName'][$dbHttpTest['name']] = $dbHttpTest;
if ($dbHttpTest['templateid']) {
$hostHttpTests[$dbHttpTest['hostid']]['byTemplateId'][$dbHttpTest['templateid']] = $dbHttpTest;
}
}
return $hostHttpTests;
}
/**
* Compare steps for http tests.
*
* @param array $httpTest steps must be included under 'steps'
* @param array $exHttpTest
*
* @return bool
*/
protected function compareHttpSteps(array $httpTest, array $exHttpTest) {
$firstHash = '';
$secondHash = '';
CArrayHelper::sort($httpTest['steps'], ['no']);
foreach ($httpTest['steps'] as $step) {
$firstHash .= $step['no'].$step['name'];
}
$dbHttpTestSteps = DBfetchArray(DBselect(
'SELECT hs.name,hs.no'.
' FROM httpstep hs'.
' WHERE hs.httptestid='.zbx_dbstr($exHttpTest['httptestid'])
));
CArrayHelper::sort($dbHttpTestSteps, ['no']);
foreach ($dbHttpTestSteps as $dbHttpStep) {
$secondHash .= $dbHttpStep['no'].$dbHttpStep['name'];
}
return ($firstHash === $secondHash);
}
/**
* Save http tests. If http test has httptestid it gets updated otherwise a new one is created.
*
* @param array $http_tests
*
* @return array
*/
protected function save(array $http_tests) {
$http_tests_to_create = [];
$http_tests_to_update = [];
foreach ($http_tests as $num => $http_test) {
if (array_key_exists('httptestid', $http_test)) {
$http_tests_to_update[] = $http_test;
}
else {
$http_tests_to_create[] = $http_test;
}
/*
* Unset $http_tests and (later) put it back with actual httptestid as a key right after creating/updating
* it. This is done in such a way because $http_tests array holds items with incremental keys which are not
* a real httptestids.
*/
unset($http_tests[$num]);
}
if ($http_tests_to_create) {
$new_http_tests = $this->create($http_tests_to_create);
foreach ($new_http_tests as $new_http_test) {
$http_tests[$new_http_test['httptestid']] = $new_http_test;
}
}
if ($http_tests_to_update) {
$updated_http_tests = $this->update($http_tests_to_update);
foreach ($updated_http_tests as $updated_http_test) {
$http_tests[$updated_http_test['httptestid']] = $updated_http_test;
}
}
return $http_tests;
}
/**
* @param array $steps
* @param $exHttpTestId
*
* @return array
*/
protected function prepareHttpSteps(array $steps, $exHttpTestId) {
$exSteps = [];
$dbCursor = DBselect(
'SELECT hs.httpstepid,hs.name'.
' FROM httpstep hs'.
' WHERE hs.httptestid='.zbx_dbstr($exHttpTestId)
);
while ($dbHttpStep = DBfetch($dbCursor)) {
$exSteps[$dbHttpStep['name']] = $dbHttpStep['httpstepid'];
}
$result = [];
foreach ($steps as $step) {
$parentTestId = $this->httpTestParents[$exHttpTestId];
if (isset($this->changedSteps[$parentTestId][$step['name']])) {
$stepName = $this->changedSteps[$parentTestId][$step['name']];
}
else {
$stepName = $step['name'];
}
if (isset($exSteps[$stepName])) {
$step['httpstepid'] = $exSteps[$stepName];
}
else {
unset($step['httpstepid']);
}
if (array_key_exists('variables', $step)) {
foreach ($step['variables'] as &$variable) {
unset($variable['httpstep_fieldid']);
}
unset($variable);
}
$result[] = $step;
}
return $result;
}
/**
* Get item key for test item.
*
* @param int $type
* @param string $test_name
*
* @return string
*/
protected static function getTestKey(int $type, string $test_name): string {
switch ($type) {
case HTTPSTEP_ITEM_TYPE_IN:
return 'web.test.in['.quoteItemKeyParam($test_name).',,bps]';
case HTTPSTEP_ITEM_TYPE_LASTSTEP:
return 'web.test.fail['.quoteItemKeyParam($test_name).']';
case HTTPSTEP_ITEM_TYPE_LASTERROR:
return 'web.test.error['.quoteItemKeyParam($test_name).']';
}
return 'unknown';
}
/**
* Get item name for test item.
*
* @param int $type
* @param string $test_name
*
* @return string
*/
private static function getTestName(int $type, string $test_name): string {
switch ($type) {
case HTTPSTEP_ITEM_TYPE_IN:
return 'Download speed for scenario "'.$test_name.'".';
case HTTPSTEP_ITEM_TYPE_LASTSTEP:
return 'Failed step of scenario "'.$test_name.'".';
case HTTPSTEP_ITEM_TYPE_LASTERROR:
return 'Last error message of scenario "'.$test_name.'".';
}
return 'unknown';
}
/**
* Get item key for step item.
*
* @param int $type
* @param string $test_name
* @param string $step_name
*
* @return string
*/
private static function getStepKey(int $type, string $test_name, string $step_name): string {
switch ($type) {
case HTTPSTEP_ITEM_TYPE_IN:
return 'web.test.in['.quoteItemKeyParam($test_name).','.quoteItemKeyParam($step_name).',bps]';
case HTTPSTEP_ITEM_TYPE_TIME:
return 'web.test.time['.quoteItemKeyParam($test_name).','.quoteItemKeyParam($step_name).',resp]';
case HTTPSTEP_ITEM_TYPE_RSPCODE:
return 'web.test.rspcode['.quoteItemKeyParam($test_name).','.quoteItemKeyParam($step_name).']';
}
return 'unknown';
}
/**
* Get item name for step item.
*
* @param int $type
* @param string $test_name
* @param string $step_name
*
* @return string
*/
private static function getStepName(int $type, string $test_name, string $step_name): string {
switch ($type) {
case HTTPSTEP_ITEM_TYPE_IN:
return 'Download speed for step "'.$step_name.'" of scenario "'.$test_name.'".';
case HTTPSTEP_ITEM_TYPE_TIME:
return 'Response time for step "'.$step_name.'" of scenario "'.$test_name.'".';
case HTTPSTEP_ITEM_TYPE_RSPCODE:
return 'Response code for step "'.$step_name.'" of scenario "'.$test_name.'".';
}
return 'unknown';
}
/**
* Returns the data about the last execution of the given HTTP tests.
*
* The following values will be returned for each executed HTTP test:
* - lastcheck - time when the test has been executed last
* - lastfailedstep - number of the last failed step
* - error - error message
*
* If a HTTP test has not been executed in last CSettingsHelper::HISTORY_PERIOD, no value will be returned.
*
* @param array $httpTestIds
*
* @return array an array with HTTP test IDs as keys and arrays of data as values
*/
public function getLastData(array $httpTestIds) {
$httpItems = DBfetchArray(DBselect(
'SELECT hti.httptestid,hti.type,i.itemid,i.value_type'.
' FROM httptestitem hti,items i'.
' WHERE hti.itemid=i.itemid'.
' AND hti.type IN ('.HTTPSTEP_ITEM_TYPE_LASTSTEP.','.HTTPSTEP_ITEM_TYPE_LASTERROR.')'.
' AND '.dbConditionInt('hti.httptestid', $httpTestIds)
));
$history = Manager::History()->getLastValues($httpItems, 1, timeUnitToSeconds(CSettingsHelper::get(
CSettingsHelper::HISTORY_PERIOD
)));
$data = [];
foreach ($httpItems as $httpItem) {
if (isset($history[$httpItem['itemid']])) {
if (!isset($data[$httpItem['httptestid']])) {
$data[$httpItem['httptestid']] = [
'lastcheck' => null,
'lastfailedstep' => null,
'error' => null
];
}
$itemHistory = $history[$httpItem['itemid']][0];
if ($httpItem['type'] == HTTPSTEP_ITEM_TYPE_LASTSTEP) {
$data[$httpItem['httptestid']]['lastcheck'] = $itemHistory['clock'];
$data[$httpItem['httptestid']]['lastfailedstep'] = $itemHistory['value'];
}
else {
$data[$httpItem['httptestid']]['error'] = $itemHistory['value'];
}
}
}
return $data;
}
}