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.

1106 lines
34 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.
**/
require_once dirname(__FILE__).'/../include/CIntegrationTest.php';
/**
* Test suite for action notifications
*
* @required-components server
* @configurationDataProvider serverConfigurationProvider
* @backup items,actions,triggers,alerts
* @hosts test_actions
*/
class testEscalations extends CIntegrationTest {
private static $hostid;
private static $triggerid;
private static $maint_start_tm;
private static $trigger_actionid;
private static $scriptid_problem;
private static $scriptid_recovery;
const TRAPPER_ITEM_NAME = 'trap';
const HOST_NAME = 'test_actions';
const COMMAND_PROBLEM = 'echo "problem"';
const COMMAND_RECOVERY = 'echo "recovery"';
/**
* @inheritdoc
*/
public function prepareData() {
// Create host "testhost".
$response = $this->call('host.create', [
'host' => self::HOST_NAME,
'interfaces' => [
'type' => 1,
'main' => 1,
'useip' => 1,
'ip' => '127.0.0.1',
'dns' => '',
'port' => $this->getConfigurationValue(self::COMPONENT_AGENT, 'ListenPort')
],
'groups' => ['groupid' => 4]
]);
$this->assertArrayHasKey('hostids', $response['result']);
$this->assertArrayHasKey(0, $response['result']['hostids']);
self::$hostid = $response['result']['hostids'][0];
// Get host interface ids.
$response = $this->call('host.get', [
'output' => ['host'],
'hostids' => [self::$hostid],
'selectInterfaces' => ['interfaceid']
]);
$this->assertArrayHasKey(0, $response['result']);
$this->assertArrayHasKey('interfaces', $response['result'][0]);
$this->assertArrayHasKey(0, $response['result'][0]['interfaces']);
// Create trapper item
$response = $this->call('item.create', [
'hostid' => self::$hostid,
'name' => self::TRAPPER_ITEM_NAME,
'key_' => self::TRAPPER_ITEM_NAME,
'type' => ITEM_TYPE_TRAPPER,
'value_type' => ITEM_VALUE_TYPE_UINT64
]);
$this->assertArrayHasKey('itemids', $response['result']);
$this->assertEquals(1, count($response['result']['itemids']));
// Create trigger
$response = $this->call('trigger.create', [
'description' => 'Trapper received 1',
'expression' => 'last(/'.self::HOST_NAME.'/'.self::TRAPPER_ITEM_NAME.')>0'
]);
$this->assertArrayHasKey('triggerids', $response['result']);
$this->assertEquals(1, count($response['result']['triggerids']));
self::$triggerid = $response['result']['triggerids'][0];
// Create trigger action
$response = $this->call('action.create', [
'esc_period' => '1h',
'eventsource' => EVENT_SOURCE_TRIGGERS,
'status' => ACTION_STATUS_ENABLED,
'filter' => [
'conditions' => [
[
'conditiontype' => CONDITION_TYPE_TRIGGER,
'operator' => CONDITION_OPERATOR_EQUAL,
'value' => self::$triggerid
]
],
'evaltype' => CONDITION_EVAL_TYPE_AND_OR
],
'name' => 'Trapper received 1 (problem) clone',
'operations' => [
[
'esc_period' => 0,
'esc_step_from' => 1,
'esc_step_to' => 1,
'operationtype' => OPERATION_TYPE_MESSAGE,
'opmessage' => ['default_msg' => 1,
'mediatypeid' => 0
],
'opmessage_grp' => [
['usrgrpid' => 7]
]
]
],
'pause_suppressed' => 0,
'recovery_operations' => [
[
'operationtype' => OPERATION_TYPE_MESSAGE,
'opmessage' => [
'default_msg' => 1,
'mediatypeid' => 0
],
'opmessage_grp' => [
['usrgrpid' => 7]
]
]
]
]);
$this->assertArrayHasKey('actionids', $response['result']);
$this->assertEquals(1, count($response['result']['actionids']));
self::$trigger_actionid = $response['result']['actionids'][0];
// Enable mediatypes
$response = $this->call('mediatype.update', [
'mediatypeid' => 1,
'status' => 0
]);
$this->assertArrayHasKey('mediatypeids', $response['result']);
$this->assertEquals(1, count($response['result']['mediatypeids']));
return true;
}
/**
* Component configuration provider for agent related tests.
*
* @return array
*/
public function serverConfigurationProvider() {
return [
self::COMPONENT_SERVER => [
'DebugLevel' => 4,
'LogFileSize' => 20
]
];
}
/**
* Component configuration provider for remote command related tests.
*
* @return array
*/
public function serverConfigurationProviderRemote() {
return [
self::COMPONENT_SERVER => [
'DebugLevel' => 4,
'LogFileSize' => 20,
'Timeout' => 30
],
self::COMPONENT_AGENT => [
'Hostname' => self::HOST_NAME,
'ServerActive' => '127.0.0.1:'.self::getConfigurationValue(self::COMPONENT_SERVER,
'ListenPort', 10051),
'AllowKey' => 'system.run[*]',
'LogRemoteCommands' => 1
]
];
}
/**
* @backup actions,alerts,history_uint,history,problem,events
*/
public function testEscalations_disabledAction() {
$this->clearLog(self::COMPONENT_SERVER);
$response = $this->call('action.update', [
'actionid' => self::$trigger_actionid,
'status' => 1
]);
$this->assertArrayHasKey('actionids', $response['result']);
$this->assertEquals(1, count($response['result']['actionids']));
$this->reloadConfigurationCache();
$this->sendSenderValue(self::HOST_NAME, self::TRAPPER_ITEM_NAME, 1);
// Check if there are no alerts for this action
$response = $this->call('alert.get', [
'actionids' => [self::$trigger_actionid]
]);
$this->assertEmpty($response['result']);
$this->sendSenderValue(self::HOST_NAME, self::TRAPPER_ITEM_NAME, 0);
}
/**
* @backup alerts,triggers,history_uint,history,problem,events
*/
public function testEscalations_disabledTrigger() {
$this->clearLog(self::COMPONENT_SERVER);
$response = $this->call('trigger.update', [
'triggerid' => self::$triggerid,
'status' => 1
]);
$this->assertArrayHasKey('triggerids', $response['result']);
$this->assertEquals(1, count($response['result']['triggerids']));
$this->reloadConfigurationCache();
$this->sendSenderValue(self::HOST_NAME, self::TRAPPER_ITEM_NAME, 2);
// Check if there are no alerts for this action
$response = $this->call('alert.get', [
'actionids' => [self::$trigger_actionid]
]);
$this->assertEmpty($response['result']);
$this->sendSenderValue(self::HOST_NAME, self::TRAPPER_ITEM_NAME, 0);
}
/**
* Test maintenance scenario:
* disable pause_suppressed
* maintenance on
* event -> alert
* recovery -> alert
*
* @backup alerts,history,history_uint,maintenances,events,problem
*/
public function testEscalations_checkScenario1() {
$this->clearLog(self::COMPONENT_SERVER);
$this->reloadConfigurationCache();
// Create maintenance period
self::$maint_start_tm = time();
$maint_end_tm = self::$maint_start_tm + 60 * 2;
$response = $this->call('maintenance.create', [
'name' => 'Test maintenance',
'hosts' => ['hostid' => self::$hostid],
'active_since' => self::$maint_start_tm,
'active_till' => $maint_end_tm,
'tags_evaltype' => MAINTENANCE_TAG_EVAL_TYPE_AND_OR,
'timeperiods' => [
'timeperiod_type' => TIMEPERIOD_TYPE_ONETIME,
'period' => 300,
'start_date' => self::$maint_start_tm
]
]);
$this->assertArrayHasKey('maintenanceids', $response['result']);
$this->assertEquals(1, count($response['result']['maintenanceids']));
$maintenance_id = $response['result']['maintenanceids'][0];
$this->reloadConfigurationCache();
$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'End of zbx_dc_update_maintenances()', true);
$this->sendSenderValue(self::HOST_NAME, self::TRAPPER_ITEM_NAME, 3);
$response = $this->callUntilDataIsPresent('alert.get', [
'actionids' => [self::$trigger_actionid]
], 5, 2);
$this->assertArrayHasKey(0, $response['result']);
$this->assertEquals(0, $response['result'][0]['p_eventid']);
$this->sendSenderValue(self::HOST_NAME, self::TRAPPER_ITEM_NAME, 0);
$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'In escalation_execute()', true, 120);
$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'End of escalation_execute()', true, 10, 3);
$response = $this->callUntilDataIsPresent('alert.get', [
'actionids' => [self::$trigger_actionid],
'sortfield' => 'alertid'
], 5, 2);
$this->assertArrayHasKey(1, $response['result']);
$this->assertNotEquals(0, $response['result'][1]['p_eventid']);
}
/**
* Test maintenance scenario:
* event -> alert
* maintenance on
* recovery -> alert
*
* @backup actions,alerts,history_uint,maintenances
*/
public function testEscalations_checkScenario2() {
$this->clearLog(self::COMPONENT_SERVER);
$response = $this->call('action.update', [
'actionid' => self::$trigger_actionid,
'pause_suppressed' => 1
]);
// Create maintenance period
self::$maint_start_tm = time() + 10;
$maint_end_tm = self::$maint_start_tm + 60 * 2;
$response = $this->call('maintenance.create', [
'name' => 'Test maintenance',
'hosts' => ['hostid' => self::$hostid],
'active_since' => self::$maint_start_tm,
'active_till' => $maint_end_tm,
'tags_evaltype' => MAINTENANCE_TAG_EVAL_TYPE_AND_OR,
'timeperiods' => [
'timeperiod_type' => TIMEPERIOD_TYPE_ONETIME,
'period' => 300,
'start_date' => self::$maint_start_tm
]
]);
$this->assertArrayHasKey('maintenanceids', $response['result']);
$this->assertEquals(1, count($response['result']['maintenanceids']));
$maintenance_id = $response['result']['maintenanceids'][0];
$this->reloadConfigurationCache();
$this->sendSenderValue(self::HOST_NAME, self::TRAPPER_ITEM_NAME, 4);
$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'In escalation_execute()', true, 120);
$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'End of escalation_execute()', true, 10, 3);
$response = $this->callUntilDataIsPresent('alert.get', [
'actionids' => [self::$trigger_actionid]
], 5, 2);
$this->assertArrayHasKey(0, $response['result']);
$this->assertEquals(0, $response['result'][0]['p_eventid']);
$this->waitForLogLineToBePresent(self::COMPONENT_SERVER,
'End of zbx_dc_update_maintenances() started:1 stopped:0 running:1', true);
$this->sendSenderValue(self::HOST_NAME, self::TRAPPER_ITEM_NAME, 0);
$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'In escalation_recover()', true, 120);
$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'End of escalation_recover()', true);
$response = $this->callUntilDataIsPresent('alert.get', [
'actionids' => [self::$trigger_actionid],
'sortfield' => 'alertid'
], 5, 2);
$this->assertArrayHasKey(1, $response['result']);
$this->assertNotEquals(0, $response['result'][1]['p_eventid']);
}
/**
* Test maintenance scenario:
* maintenance on
* event -> nothing
* maintenance off -> alert
* recovery -> alert
*
* @backup actions,alerts,history_uint,maintenances
*/
public function testEscalations_checkScenario3() {
$this->clearLog(self::COMPONENT_SERVER);
$response = $this->call('action.update', [
'actionid' => self::$trigger_actionid,
'pause_suppressed' => 1
]);
// Create maintenance period
self::$maint_start_tm = time();
$maint_end_tm = self::$maint_start_tm + 60 * 2;
$response = $this->call('maintenance.create', [
'name' => 'Test maintenance',
'hosts' => ['hostid' => self::$hostid],
'active_since' => self::$maint_start_tm,
'active_till' => $maint_end_tm,
'tags_evaltype' => MAINTENANCE_TAG_EVAL_TYPE_AND_OR,
'timeperiods' => [
'timeperiod_type' => TIMEPERIOD_TYPE_ONETIME,
'period' => 300,
'start_date' => self::$maint_start_tm
]
]);
$this->assertArrayHasKey('maintenanceids', $response['result']);
$this->assertEquals(1, count($response['result']['maintenanceids']));
$maintenance_id = $response['result']['maintenanceids'][0];
$this->reloadConfigurationCache();
$this->waitForLogLineToBePresent(self::COMPONENT_SERVER,
'End of zbx_dc_update_maintenances() started:1 stopped:0 running:1', true);
$this->sendSenderValue(self::HOST_NAME, self::TRAPPER_ITEM_NAME, 5);
$response = $this->call('alert.get', [
'actionids' => [self::$trigger_actionid]
]);
$this->assertEmpty($response['result']);
$response = $this->call('maintenance.delete', [
$maintenance_id
]);
$this->assertArrayHasKey('maintenanceids', $response['result']);
$this->assertEquals($maintenance_id, $response['result']['maintenanceids'][0]);
$this->reloadConfigurationCache();
$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'In zbx_dc_update_maintenances()|In escalation_execute()', true, 120, null, true);
$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'End of zbx_dc_update_maintenances()|End of escalation_execute()', true, null, 3, true);
$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'In escalation_execute()|In zbx_dc_update_maintenances()', true, 120, null, true);
$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'End of escalation_execute()|End of zbx_dc_update_maintenances()', true, null, 3, true);
$response = $this->callUntilDataIsPresent('alert.get', [
'actionids' => [self::$trigger_actionid]
], 5, 2);
$this->assertArrayHasKey(0, $response['result']);
$this->assertEquals(0, $response['result'][0]['p_eventid']);
$this->sendSenderValue(self::HOST_NAME, self::TRAPPER_ITEM_NAME, 0);
$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'In escalation_recover()', true, 120);
$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'End of escalation_recover()', true);
$response = $this->callUntilDataIsPresent('alert.get', [
'actionids' => [self::$trigger_actionid],
'sortfield' => 'alertid'
], 5, 2);
$this->assertArrayHasKey(1, $response['result']);
$this->assertNotEquals(0, $response['result'][1]['p_eventid']);
}
/**
* Test cancelled escalation (disabled trigger)
*
* @backup actions,alerts,events,problem,history_uint,hosts,users
*/
public function testEscalations_checkScenario4() {
$this->clearLog(self::COMPONENT_SERVER);
$response = $this->call('action.update', [
'actionid' => self::$trigger_actionid,
'operations' => [
[
'esc_period' => '1m',
'esc_step_from' => 1,
'esc_step_to' => 1,
'evaltype' => 0,
'operationtype' => OPERATION_TYPE_MESSAGE,
'opmessage' => [
'default_msg' => 0,
'mediatypeid' => 1,
'message' => 'Problem',
'subject' => 'Problem'
],
'opmessage_grp' => [['usrgrpid' => 7]]
],
[
'esc_period' => '1m',
'esc_step_from' => 2,
'esc_step_to' => 2,
'evaltype' => 0,
'operationtype' => OPERATION_TYPE_MESSAGE,
'opmessage' => [
'default_msg' => 0,
'mediatypeid' => 1,
'message' => 'Problem',
'subject' => 'Problem'
],
'opmessage_grp' => [['usrgrpid' => 7]]
]
]
]);
$this->assertArrayHasKey('actionids', $response['result']);
$this->assertArrayHasKey(0, $response['result']['actionids']);
$response = $this->call('user.update', [
'userid' => 1,
'medias' => [
[
'mediatypeid' => 1,
'sendto' => 'test@local.local'
]
]
]);
$this->assertArrayHasKey('userids', $response['result']);
$this->assertArrayHasKey(0, $response['result']['userids']);
$this->reloadConfigurationCache();
$this->sendSenderValue(self::HOST_NAME, self::TRAPPER_ITEM_NAME, 6);
$response = $this->call('trigger.update', [
'triggerid' => self::$triggerid,
'status' => 1
]);
$this->assertArrayHasKey('triggerids', $response['result']);
$this->assertEquals(1, count($response['result']['triggerids']));
$this->reloadConfigurationCache();
$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'End of escalation_cancel()', true, 120);
$response = $this->callUntilDataIsPresent('alert.get', [
'actionids' => [self::$trigger_actionid],
'sortfield' => 'alertid'
], 5, 2);
$esc_msg = 'NOTE: Escalation canceled';
$this->assertArrayHasKey(1, $response['result']);
$this->assertEquals(0, strncmp($esc_msg, $response['result'][1]['message'], strlen($esc_msg)));
// trigger value is not updated during configuration cache sync (only initialized)
// therefore need to restore it manually by sending OK value
$response = $this->call('trigger.update', [
'triggerid' => self::$triggerid,
'status' => 0
]);
$this->reloadConfigurationCache();
$this->sendSenderValue(self::HOST_NAME, self::TRAPPER_ITEM_NAME, 0);
// test ability to disable notifications about cancelled escalations
$response = $this->call('action.update', [
'actionid' => self::$trigger_actionid,
'notify_if_canceled' => 0
]);
$this->assertArrayHasKey('actionids', $response['result']);
$this->assertArrayHasKey(0, $response['result']['actionids']);
$this->reloadConfigurationCache();
$this->sendSenderValue(self::HOST_NAME, self::TRAPPER_ITEM_NAME, 10);
$response = $this->call('trigger.update', [
'triggerid' => self::$triggerid,
'status' => 1
]);
$this->assertArrayHasKey('triggerids', $response['result']);
$this->assertEquals(1, count($response['result']['triggerids']));
$this->reloadConfigurationCache();
$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'End of escalation_cancel()', true, 120);
$response = $this->callUntilDataIsPresent('alert.get', [
'actionids' => [self::$trigger_actionid],
'sortfield' => 'alertid',
'sortorder' => 'DESC'
], 5, 2);
$this->assertArrayHasKey(0, $response['result']);
$this->assertNotEquals(0, strncmp($esc_msg, $response['result'][0]['message'], strlen($esc_msg)));
// revert to defaults, restore trigger status and value
$response = $this->call('action.update', [
'actionid' => self::$trigger_actionid,
'notify_if_canceled' => 1
]);
$this->assertArrayHasKey('actionids', $response['result']);
$this->assertArrayHasKey(0, $response['result']['actionids']);
$response = $this->call('trigger.update', [
'triggerid' => self::$triggerid,
'status' => 0
]);
$this->assertArrayHasKey('triggerids', $response['result']);
$this->assertEquals(1, count($response['result']['triggerids']));
$this->reloadConfigurationCache();
$this->sendSenderValue(self::HOST_NAME, self::TRAPPER_ITEM_NAME, 0);
}
/**
* Test normal escalation with multiple escalations steps
*
* @backup alerts,actions
*/
public function testEscalations_checkScenario5() {
$this->clearLog(self::COMPONENT_SERVER);
$this->reloadConfigurationCache();
$response = $this->call('action.update', [
'actionid' => self::$trigger_actionid,
'esc_period' => '1m',
'operations' => [
[
'esc_period' => 0,
'esc_step_from' => 1,
'esc_step_to' => 1,
'evaltype' => 0,
'operationtype' => OPERATION_TYPE_MESSAGE,
'opmessage' => [
'default_msg' => 0,
'mediatypeid' => 0,
'message' => 'Cause problem 1',
'subject' => 'Cause problem 1'
],
'opmessage_grp' => [['usrgrpid' => 7]]
],
[
'esc_period' => 0,
'esc_step_from' => 2,
'esc_step_to' => 2,
'evaltype' => 0,
'operationtype' => OPERATION_TYPE_MESSAGE,
'opmessage' => [
'default_msg' => 0,
'mediatypeid' => 0,
'message' => 'Cause problem 2',
'subject' => 'Cause problem 2'
],
'opmessage_grp' => [['usrgrpid' => 7]]
]
]
]);
$this->assertArrayHasKey('actionids', $response['result']);
$this->assertArrayHasKey(0, $response['result']['actionids']);
// create items, triggers, actions for testing symptom events
$pause_symptoms = [
1 => ACTION_PAUSE_SYMPTOMS_TRUE,
2 => ACTION_PAUSE_SYMPTOMS_FALSE
];
$trapper_keys = [];
$symptom_triggerids = [];
$symptom_actionids = [];
foreach ([1, 2] as $i) {
// Create trapper item
$name = $key = self::TRAPPER_ITEM_NAME."_s".(string)$i;
$trapper_keys[$i] = $key;
$response = $this->call('item.create', [
'hostid' => self::$hostid,
'name' => $name,
'key_' => $key,
'type' => ITEM_TYPE_TRAPPER,
'value_type' => ITEM_VALUE_TYPE_UINT64
]);
$this->assertArrayHasKey('itemids', $response['result']);
$this->assertCount(1, $response['result']['itemids']);
// Create trigger
$response = $this->call('trigger.create', [
'description' => 'Mandatory description',
'expression' => 'last(/'.self::HOST_NAME.'/'.$key.')>0'
]);
$this->assertArrayHasKey('triggerids', $response['result']);
$this->assertCount(1, $response['result']['triggerids']);
$symptom_triggerids[$i] = $response['result']['triggerids'][0];
// Create action
$response = $this->call('action.create', [
'esc_period' => '1m',
'eventsource' => EVENT_SOURCE_TRIGGERS,
'status' => ACTION_STATUS_ENABLED,
'pause_symptoms' => $pause_symptoms[$i],
'filter' => [
'conditions' => [
[
'conditiontype' => CONDITION_TYPE_TRIGGER,
'operator' => CONDITION_OPERATOR_EQUAL,
'value' => $symptom_triggerids[$i]
]
],
'evaltype' => CONDITION_EVAL_TYPE_AND_OR
],
'name' => 'Symptom action '.(string)$i,
'operations' => [
[
'esc_period' => 0,
'esc_step_from' => 1,
'esc_step_to' => 1,
'evaltype' => 0,
'operationtype' => OPERATION_TYPE_MESSAGE,
'opmessage' => [
'default_msg' => 0,
'mediatypeid' => 0,
'message' => 'Symptom problem 1',
'subject' => 'Symptom problem 1'
],
'opmessage_grp' => [['usrgrpid' => 7]]
],
[
'esc_period' => 0,
'esc_step_from' => 2,
'esc_step_to' => 2,
'evaltype' => 0,
'operationtype' => OPERATION_TYPE_MESSAGE,
'opmessage' => [
'default_msg' => 0,
'mediatypeid' => 0,
'message' => 'Symptom problem 2',
'subject' => 'Symptom problem 2'
],
'opmessage_grp' => [['usrgrpid' => 7]]
]
]
]);
$this->assertArrayHasKey('actionids', $response['result']);
$this->assertCount(1, $response['result']['actionids']);
$symptom_actionids[$i] = $response['result']['actionids'][0];
}
$this->reloadConfigurationCache();
// start all events as causes, because only existing events can be ranked as symptoms
$this->sendSenderValue(self::HOST_NAME, self::TRAPPER_ITEM_NAME, 7);
$this->sendSenderValue(self::HOST_NAME, $trapper_keys[1], 7);
$this->sendSenderValue(self::HOST_NAME, $trapper_keys[2], 7);
$response = $this->callUntilDataIsPresent('problem.get', [
'output' => ['eventid'],
'objectids' => [self::$triggerid, $symptom_triggerids[1], $symptom_triggerids[2]]
]);
$this->assertCount(3, $response['result']);
$this->assertArrayHasKey('eventid', $response['result'][0]);
$this->assertArrayHasKey('eventid', $response['result'][1]);
$this->assertArrayHasKey('eventid', $response['result'][2]);
$cause_eventid = $response['result'][0]['eventid'];
// these events are causes at this point and will be ranked as symptoms later
$symptom_eventids[1] = $response['result'][1]['eventid'];
$symptom_eventids[2] = $response['result'][2]['eventid'];
// wait until escalation step 1 is completed for all three events
for ($i = 0; $i < 3; $i++) {
$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'In escalation_execute()', true, 95, 3);
$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'End of escalation_execute()', true, 10, 3);
}
// rank 2 events as symptom events
$response = $this->call('event.acknowledge', [
'eventids' => $symptom_eventids,
'action' => ZBX_PROBLEM_UPDATE_RANK_TO_SYMPTOM,
'cause_eventid' => $cause_eventid
]);
$this->assertArrayHasKey('result', $response);
$this->assertArrayHasKey('eventids', $response['result']);
$this->assertCount(2, $response['result']['eventids']);
// Escalations are expected for 2 events:
// 1. the cause event;
// 2. one symptom event with ACTION_PAUSE_SYMPTOMS_FALSE.
for ($i = 0; $i < 2; $i++) {
$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'In escalation_execute()', true, 95, 3);
$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'End of escalation_execute()', true, 10, 3);
}
// check alerts for the cause event
$response = $this->callUntilDataIsPresent('alert.get', [
'output' => 'extend',
'actionids' => [self::$trigger_actionid],
'sortfield' => 'alertid'
], 5, 2);
// 2 escalations are expected
$this->assertCount(2, $response['result']);
$this->assertEquals(1, $response['result'][0]['esc_step']);
$this->assertEquals(2, $response['result'][1]['esc_step']);
// check alerts for the symptom event with ACTION_PAUSE_SYMPTOMS_TRUE
$response = $this->callUntilDataIsPresent('alert.get', [
'output' => 'extend',
'actionids' => $symptom_actionids[1],
'sortfield' => 'alertid'
], 5, 2);
// 1 escalation is expected
$this->assertCount(1, $response['result']);
$this->assertEquals(1, $response['result'][0]['esc_step']);
// check alerts for the symptom event with ACTION_PAUSE_SYMPTOMS_FALSE
$response = $this->callUntilDataIsPresent('alert.get', [
'output' => 'extend',
'actionids' => $symptom_actionids[2],
'sortfield' => 'alertid'
], 5, 2);
// 2 escalations are expected
$this->assertCount(2, $response['result']);
$this->assertEquals(1, $response['result'][0]['esc_step']);
$this->assertEquals(2, $response['result'][1]['esc_step']);
// stop events
$this->sendSenderValue(self::HOST_NAME, self::TRAPPER_ITEM_NAME, 0);
$this->sendSenderValue(self::HOST_NAME, $trapper_keys[1], 0);
$this->sendSenderValue(self::HOST_NAME, $trapper_keys[2], 0);
}
/**
* Test unfinished webhook
*testEscalations_checkUnfinishedAlerts
* @backup actions, alerts, history_uint, media_type, users, media, events, problem
*/
public function testEscalations_checkUnfinishedAlerts() {
$this->clearLog(self::COMPONENT_SERVER);
$this->reloadConfigurationCache();
// Create webhook mediatype
$script_code = <<<HEREDOC
var params = JSON.parse(value);
if (!(params.event_value === '0' || params.event_update_status === '1')) {
var now = new Date().getTime();
while (new Date().getTime() < now + 11000) { /* do nothing */ }
}
return {};
HEREDOC;
$response = $this->call('mediatype.create', [
'script' => $script_code,
'name' => 'Long executing webhook',
'timeout' => '30s',
'type' => MEDIA_TYPE_WEBHOOK,
'parameters' => [
[
'name' => 'event_value',
'value' => '{EVENT.VALUE}'
],
[
'name' => 'event_update_status',
'value' => '{EVENT.SOURCE}'
]
],
'content_type' => 1,
'status' => 0
]);
$this->assertArrayHasKey('mediatypeids', $response['result']);
$this->assertEquals(1, count($response['result']['mediatypeids']));
$mediatypeid = $response['result']['mediatypeids'][0];
$response = $this->call('user.update', [
'userid' => 1,
'medias' => [
[
'mediatypeid' => $mediatypeid,
'sendto' => 'q'
]
]
]);
$this->assertArrayHasKey('userids', $response['result']);
$this->assertArrayHasKey(0, $response['result']['userids']);
// Create action
$response = $this->call('action.create', [
'esc_period' => '1h',
'eventsource' => 0,
'status' => 0,
'filter' => [
'conditions' => [
[
'conditiontype' => CONDITION_TYPE_TRIGGER,
'operator' => CONDITION_OPERATOR_EQUAL,
'value' => self::$triggerid
]
],
'evaltype' => 0
],
'name' => 'Trapper received 1 (unfinished alert check)',
'operations' => [
[
'esc_period' => 0,
'esc_step_from' => 1,
'esc_step_to' => 1,
'operationtype' => OPERATION_TYPE_MESSAGE,
'opmessage' => [
'default_msg' => 0,
'mediatypeid' => $mediatypeid,
'subject' => 's',
'message' => 's'
],
'opmessage_grp' => [['usrgrpid' => 7]]
]
],
'pause_suppressed' => 0,
'recovery_operations' => [
[
'operationtype' => OPERATION_TYPE_RECOVERY_MESSAGE,
'opmessage' => [
'default_msg' => 0,
'subject' => 'R',
'message' => 'R'
]
]
]
]);
$this->assertArrayHasKey('actionids', $response['result']);
$this->assertEquals(1, count($response['result']['actionids']));
$actionid = $response['result']['actionids'];
$response = $this->call('action.update', [
'actionid' => self::$trigger_actionid,
'status' => 1
]);
$this->reloadConfigurationCache();
$this->sendSenderValue(self::HOST_NAME, self::TRAPPER_ITEM_NAME, 8);
$this->sendSenderValue(self::HOST_NAME, self::TRAPPER_ITEM_NAME, 0);
$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'In escalation_execute()', true, 95, 3);
$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'End of escalation_execute()', true, 10, 3);
$response = $this->callUntilDataIsPresent('alert.get', [
'actionids' => $actionid
], 5, 2);
$this->assertCount(1, $response['result']);
$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'In escalation_recover()', true, 200);
$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'End of escalation_recover()', true);
$response = $this->callUntilDataIsPresent('alert.get', [
'actionids' => $actionid
], 5, 2);
$this->assertCount(2, $response['result']);
}
/**
* Test active remote commands
*testEscalations_checkActiveCommands
* @required-components server, agent
* @configurationDataProvider serverConfigurationProviderRemote
* @backup actions, alerts, history_uint, media_type, users, media, events, problem
*/
public function testEscalations_checkActiveCommands() {
$this->clearLog(self::COMPONENT_SERVER);
$this->reloadConfigurationCache();
// Create remote commands
$response = $this->call('script.create', [
'name' => 'Test remote command problem',
'command' => self::COMMAND_PROBLEM,
'execute_on' => 0,
'scope' => 1,
'type' => 0
]);
$this->assertArrayHasKey('scriptids', $response['result']);
self::$scriptid_problem = $response['result']['scriptids'][0];
$response = $this->call('script.create', [
'name' => 'Test remote command recovery',
'command' => self::COMMAND_RECOVERY,
'execute_on' => 0,
'scope' => 1,
'type' => 0
]);
$this->assertArrayHasKey('scriptids', $response['result']);
self::$scriptid_recovery = $response['result']['scriptids'][0];
// Create active item
$response = $this->call('item.create', [
'hostid' => self::$hostid,
'name' => 'Agent variant',
'key_' => 'agent.variant',
'type' => ITEM_TYPE_ZABBIX_ACTIVE,
'value_type' => ITEM_VALUE_TYPE_UINT64,
'delay' => '1s'
]);
$this->assertArrayHasKey('itemids', $response['result']);
$this->assertEquals(1, count($response['result']['itemids']));
// Create action
$response = $this->call('action.create', [
'esc_period' => '1h',
'eventsource' => 0,
'status' => 0,
'filter' => [
'conditions' => [
[
'conditiontype' => CONDITION_TYPE_TRIGGER,
'operator' => CONDITION_OPERATOR_EQUAL,
'value' => self::$triggerid
]
],
'evaltype' => 0
],
'name' => 'Remote command action',
'operations' => [
[
'esc_period' => 0,
'esc_step_from' => 1,
'esc_step_to' => 1,
'operationtype' => OPERATION_TYPE_COMMAND,
'opcommand' => [
'scriptid' => self::$scriptid_problem
],
'opcommand_hst' => [
[
'hostid'=> self::$hostid
]
]
]
],
'pause_suppressed' => 0,
'recovery_operations' => [
[
'operationtype' => OPERATION_TYPE_COMMAND,
'opcommand' => [
'scriptid' => self::$scriptid_recovery
],
'opcommand_hst' => [
[
'hostid'=> self::$hostid
]
]
]
]
]);
$this->assertArrayHasKey('actionids', $response['result']);
$this->assertEquals(1, count($response['result']['actionids']));
$actionid = $response['result']['actionids'];
$response = $this->call('action.update', [
'actionid' => self::$trigger_actionid,
'status' => 1
]);
$this->reloadConfigurationCache();
$this->sendSenderValue(self::HOST_NAME, self::TRAPPER_ITEM_NAME, 8);
$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'In escalation_execute()', true, 95, 3);
$this->waitForLogLineToBePresent(self::COMPONENT_AGENT, "Executing command '".self::COMMAND_PROBLEM."'",
true, 10, 3);
$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'End of zbx_process_command_results(), parsed 1',
true);
$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'End of escalation_execute()', true, 10, 3);
$response = $this->callUntilDataIsPresent('alert.get', [
'actionids' => $actionid
], 5, 2);
$this->assertCount(1, $response['result']);
$this->sendSenderValue(self::HOST_NAME, self::TRAPPER_ITEM_NAME, 0);
$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'In escalation_recover()', true, 200);
$this->waitForLogLineToBePresent(self::COMPONENT_AGENT, "Executing command '".self::COMMAND_RECOVERY."'",
true, 10, 3);
$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'End of zbx_process_command_results(), parsed 1',
true);
$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'End of escalation_recover()', true);
$response = $this->callUntilDataIsPresent('alert.get', [
'actionids' => $actionid
], 5, 2);
$this->assertCount(2, $response['result']);
}
/**
* @backup actions, alerts, history_uint
*/
public function testEscalations_triggerDependency() {
$this->clearLog(self::COMPONENT_SERVER);
// Create trigger
$response = $this->call('trigger.create', [
'description' => 'Dependent trigger',
'expression' => 'last(/'.self::HOST_NAME.'/'.self::TRAPPER_ITEM_NAME.')>0',
'dependencies' => [
['triggerid' => self::$triggerid]
]
]);
$this->assertArrayHasKey('triggerids', $response['result']);
$this->assertEquals(1, count($response['result']['triggerids']));
$dep_triggerid = $response['result']['triggerids'][0];
$response = $this->call('action.update', [
'actionid' => self::$trigger_actionid,
'filter' => [
'conditions' => [
[
'conditiontype' => '2',
'operator' => 0,
'value' => $dep_triggerid
]
],
'evaltype' => 0
]
]);
$this->assertArrayHasKey('actionids', $response['result']);
$this->assertEquals(1, count($response['result']['actionids']));
$this->reloadConfigurationCache();
$this->sendSenderValue(self::HOST_NAME, self::TRAPPER_ITEM_NAME, 9);
$response = $this->call('alert.get', [
'actionids' => self::$trigger_actionid
]);
$this->assertEmpty($response['result']);
$this->sendSenderValue(self::HOST_NAME, self::TRAPPER_ITEM_NAME, 0);
}
}