diff options
author | Miks Kronkalns <miks.kronkalns@zabbix.com> | 2021-12-02 11:09:09 +0300 |
---|---|---|
committer | Sergey Simonenko <sergey.simonenko@zabbix.com> | 2021-12-02 11:09:09 +0300 |
commit | aab41e634284fa954028e19f0945dc6d771a4667 (patch) | |
tree | 44dd2b1fe27fb10bcce0c2734580f40b0bca16e9 | |
parent | 4038a2734e64fd66406db1281bb415298c45a8d4 (diff) | |
parent | 26dcc0b43620fc086bef92acbf4d73166f8f1684 (diff) |
A.F.....S. [ZBXNEXT-6250] added option to opt-out of "escalation canceled" messages
* commit '26dcc0b43620fc086bef92acbf4d73166f8f1684':
..F....... [ZBXNEXT-6250] minor code refactoring
.......... [ZBXNEXT-6250] added new notify_if_canceled field to data.tmpl
........S. [ZBXNEXT-6250] removed redundant blank line
.......... [ZBXNEXT-6250] typo fix
.......... [ZBXNEXT-6250] typo fix
.......... [ZBXNEXT-6250] updated integration tests
........S. [ZBXNEXT-6250] changed log message string (AmE)
.D........ [ZBXNEXT-6250] fixed changelog
ADF....... [ZBXNEXT-6250] implemented escallation cancellation frontend and API part
........S. [ZBX-20177] updated constant names (server part)
........S. [ZBXNEXT-6250] changed field name
........S. [ZBXNEXT-6250] initial commit
-rw-r--r-- | ChangeLog.d/feature/ZBXNEXT-6250 | 1 | ||||
-rw-r--r-- | create/src/data.tmpl | 12 | ||||
-rw-r--r-- | create/src/schema.tmpl | 3 | ||||
-rw-r--r-- | include/common.h | 4 | ||||
-rw-r--r-- | include/db.h | 1 | ||||
-rw-r--r-- | src/libs/zbxdbupgrade/dbupgrade_5050.c | 8 | ||||
-rw-r--r-- | src/zabbix_server/actions.c | 3 | ||||
-rw-r--r-- | src/zabbix_server/escalator/escalator.c | 9 | ||||
-rw-r--r-- | ui/actionconf.php | 16 | ||||
-rw-r--r-- | ui/include/classes/api/services/CAction.php | 12 | ||||
-rw-r--r-- | ui/include/classes/api/services/CScript.php | 4 | ||||
-rw-r--r-- | ui/include/defines.inc.php | 5 | ||||
-rw-r--r-- | ui/include/schema.inc.php | 6 | ||||
-rw-r--r-- | ui/include/views/configuration.action.edit.php | 19 | ||||
-rw-r--r-- | ui/tests/integration/testEscalations.php | 53 |
15 files changed, 132 insertions, 24 deletions
diff --git a/ChangeLog.d/feature/ZBXNEXT-6250 b/ChangeLog.d/feature/ZBXNEXT-6250 new file mode 100644 index 00000000000..86b5e1e3da2 --- /dev/null +++ b/ChangeLog.d/feature/ZBXNEXT-6250 @@ -0,0 +1 @@ +A.F.....S. [ZBXNEXT-6250] added option to opt-out of "escalation canceled" messages (miks, ssimonenko) diff --git a/create/src/data.tmpl b/create/src/data.tmpl index 36c3a440eb4..0fb27f8acbd 100644 --- a/create/src/data.tmpl +++ b/create/src/data.tmpl @@ -827,12 +827,12 @@ ROW |2 |Traceroute |/usr/bin/traceroute {HOST.CONN} ROW |3 |Detect operating system|sudo /usr/bin/nmap -O {HOST.CONN} |2 |7 |NULL | | |0 |2 |2 | |0 | | | | | | TABLE |actions -FIELDS|actionid|name |eventsource|evaltype|status|esc_period|formula|pause_suppressed| -ROW |2 |Auto discovery. Linux servers. |1 |0 |1 |0 | |1 | -ROW |3 |Report problems to Zabbix administrators |0 |0 |1 |1h | |1 | -ROW |4 |Report not supported items |3 |0 |1 |1h | |1 | -ROW |5 |Report not supported low level discovery rules|3 |0 |1 |1h | |1 | -ROW |6 |Report unknown triggers |3 |0 |1 |1h | |1 | +FIELDS|actionid|name |eventsource|evaltype|status|esc_period|formula|pause_suppressed|notify_if_canceled| +ROW |2 |Auto discovery. Linux servers. |1 |0 |1 |0 | |1 |1 | +ROW |3 |Report problems to Zabbix administrators |0 |0 |1 |1h | |1 |1 | +ROW |4 |Report not supported items |3 |0 |1 |1h | |1 |1 | +ROW |5 |Report not supported low level discovery rules|3 |0 |1 |1h | |1 |1 | +ROW |6 |Report unknown triggers |3 |0 |1 |1h | |1 |1 | TABLE |operations FIELDS|operationid|actionid|operationtype|esc_period|esc_step_from|esc_step_to|evaltype|recovery| diff --git a/create/src/schema.tmpl b/create/src/schema.tmpl index 901adab5f02..2c8db70c5a7 100644 --- a/create/src/schema.tmpl +++ b/create/src/schema.tmpl @@ -390,6 +390,7 @@ FIELD |status |t_integer |'0' |NOT NULL |0 FIELD |esc_period |t_varchar(255) |'1h' |NOT NULL |0 FIELD |formula |t_varchar(255) |'' |NOT NULL |0 FIELD |pause_suppressed|t_integer |'1' |NOT NULL |0 +FIELD |notify_if_canceled|t_integer |'1' |NOT NULL |0 INDEX |1 |eventsource,status UNIQUE |2 |name @@ -1905,4 +1906,4 @@ TABLE|dbversion|dbversionid| FIELD |dbversionid |t_id | |NOT NULL |0 FIELD |mandatory |t_integer |'0' |NOT NULL | FIELD |optional |t_integer |'0' |NOT NULL | -ROW |1 |5050111 |5050111 +ROW |1 |5050112 |5050112 diff --git a/include/common.h b/include/common.h index 47f3592ec00..c91f6af45cf 100644 --- a/include/common.h +++ b/include/common.h @@ -721,6 +721,10 @@ const char *zbx_item_logtype_string(unsigned char logtype); #define ACTION_PAUSE_SUPPRESSED_FALSE 0 /* process escalation for suppressed events */ #define ACTION_PAUSE_SUPPRESSED_TRUE 1 /* pause escalation for suppressed events */ +/* action escalation canceled notification mode */ +#define ACTION_NOTIFY_IF_CANCELED_TRUE 1 /* notify about canceled escalations for action (default) */ +#define ACTION_NOTIFY_IF_CANCELED_FALSE 0 /* do not notify about canceled escalations for action */ + /* max number of retries for alerts */ #define ALERT_MAX_RETRIES 3 diff --git a/include/db.h b/include/db.h index 4d88eabebdd..a4651b3212e 100644 --- a/include/db.h +++ b/include/db.h @@ -489,6 +489,7 @@ typedef struct unsigned char pause_suppressed; unsigned char recovery; unsigned char status; + unsigned char notify_if_canceled; } DB_ACTION; diff --git a/src/libs/zbxdbupgrade/dbupgrade_5050.c b/src/libs/zbxdbupgrade/dbupgrade_5050.c index c3f68c2682e..023d29f46c6 100644 --- a/src/libs/zbxdbupgrade/dbupgrade_5050.c +++ b/src/libs/zbxdbupgrade/dbupgrade_5050.c @@ -1185,6 +1185,13 @@ static int DBpatch_5050111(void) return DBcreate_index("alerts", "alerts_8", "acknowledgeid", 0); } + +static int DBpatch_5050112(void) +{ + const ZBX_FIELD field = {"notify_if_canceled", "1", NULL, NULL, 0, ZBX_TYPE_INT, ZBX_NOTNULL, 0}; + + return DBadd_field("actions", &field); +} #endif DBPATCH_START(5050) @@ -1290,5 +1297,6 @@ DBPATCH_ADD(5050108, 0, 1) DBPATCH_ADD(5050109, 0, 1) DBPATCH_ADD(5050110, 0, 1) DBPATCH_ADD(5050111, 0, 1) +DBPATCH_ADD(5050112, 0, 1) DBPATCH_END() diff --git a/src/zabbix_server/actions.c b/src/zabbix_server/actions.c index 3962e4409a7..87c3748fb64 100644 --- a/src/zabbix_server/actions.c +++ b/src/zabbix_server/actions.c @@ -3602,7 +3602,7 @@ void get_db_actions_info(zbx_vector_uint64_t *actionids, zbx_vector_ptr_t *actio DBadd_condition_alloc(&filter, &filter_alloc, &filter_offset, "actionid", actionids->values, actionids->values_num); - result = DBselect("select actionid,name,status,eventsource,esc_period,pause_suppressed" + result = DBselect("select actionid,name,status,eventsource,esc_period,pause_suppressed,notify_if_canceled" " from actions" " where%s order by actionid", filter); @@ -3627,6 +3627,7 @@ void get_db_actions_info(zbx_vector_uint64_t *actionids, zbx_vector_ptr_t *actio zbx_free(tmp); ZBX_STR2UCHAR(action->pause_suppressed, row[5]); + ZBX_STR2UCHAR(action->notify_if_canceled, row[6]); action->name = zbx_strdup(NULL, row[1]); action->recovery = ZBX_ACTION_RECOVERY_NONE; diff --git a/src/zabbix_server/escalator/escalator.c b/src/zabbix_server/escalator/escalator.c index 4cbce93a06d..e479a095a73 100644 --- a/src/zabbix_server/escalator/escalator.c +++ b/src/zabbix_server/escalator/escalator.c @@ -1070,7 +1070,7 @@ static void add_sentusers_msg_esc_cancel(ZBX_USER_MSG **user_msg, zbx_uint64_t a user_timezone = get_user_timezone(userid); } - message_dyn = zbx_dsprintf(NULL, "NOTE: Escalation cancelled: %s\nLast message sent:\n%s", error, + message_dyn = zbx_dsprintf(NULL, "NOTE: Escalation canceled: %s\nLast message sent:\n%s", error, row[3]); tz = NULL == user_timezone || 0 == strcmp(user_timezone, "default") ? default_timezone : user_timezone; @@ -2420,7 +2420,7 @@ out: static void escalation_log_cancel_warning(const DB_ESCALATION *escalation, const char *error) { if (0 != escalation->esc_step) - zabbix_log(LOG_LEVEL_WARNING, "escalation cancelled: %s", error); + zabbix_log(LOG_LEVEL_WARNING, "escalation canceled: %s", error); } /****************************************************************************** @@ -2443,8 +2443,9 @@ static void escalation_cancel(DB_ESCALATION *escalation, const DB_ACTION *action zabbix_log(LOG_LEVEL_DEBUG, "In %s() escalationid:" ZBX_FS_UI64 " status:%s", __func__, escalation->escalationid, zbx_escalation_status_string(escalation->status)); - /* the cancellation notification can be sent if no objects are deleted */ - if (NULL != action && NULL != event && 0 != event->trigger.triggerid && 0 != escalation->esc_step) + /* the cancellation notification can be sent if no objects are deleted and notification is not disabled */ + if (NULL != action && NULL != event && 0 != event->trigger.triggerid && 0 != escalation->esc_step && + ACTION_NOTIFY_IF_CANCELED_FALSE != action->notify_if_canceled) { add_sentusers_msg_esc_cancel(&user_msg, action->actionid, event, ZBX_NULL2EMPTY_STR(error), default_timezone, service, roles); diff --git a/ui/actionconf.php b/ui/actionconf.php index 760ed6ff81a..424be7ed4b5 100644 --- a/ui/actionconf.php +++ b/ui/actionconf.php @@ -81,6 +81,11 @@ $fields = [ null, _('Pause operations for suppressed problems') ], + 'notify_if_canceled' => [T_ZBX_STR, O_OPT, null, + IN([ACTION_NOTIFY_IF_CANCELED_FALSE, ACTION_NOTIFY_IF_CANCELED_TRUE]), + null, + _('Notify about canceled escalations') + ], 'add' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 'update' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 'delete' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], @@ -248,6 +253,7 @@ if (hasRequest('add') || hasRequest('update')) { if ($eventsource == EVENT_SOURCE_TRIGGERS) { $action['pause_suppressed'] = getRequest('pause_suppressed', ACTION_PAUSE_SUPPRESSED_FALSE); + $action['notify_if_canceled'] = getRequest('notify_if_canceled', ACTION_NOTIFY_IF_CANCELED_FALSE); } switch ($eventsource) { @@ -514,7 +520,9 @@ if (hasRequest('form')) { if ($data['actionid']) { $data['action'] = API::Action()->get([ - 'output' => ['actionid', 'name', 'eventsource', 'status', 'esc_period', 'pause_suppressed'], + 'output' => ['actionid', 'name', 'eventsource', 'status', 'esc_period', 'pause_suppressed', + 'notify_if_canceled' + ], 'selectFilter' => ['evaltype', 'formula', 'conditions'], 'selectOperations' => ['operationtype', 'esc_period', 'esc_step_from', 'esc_step_to', 'evaltype', 'opconditions', 'opmessage', 'opmessage_grp', 'opmessage_usr', 'opcommand', 'opcommand_grp', @@ -556,6 +564,9 @@ if (hasRequest('form')) { if ($data['actionid'] && hasRequest('form_refresh')) { if ($data['eventsource'] == EVENT_SOURCE_TRIGGERS) { $data['action']['pause_suppressed'] = getRequest('pause_suppressed', ACTION_PAUSE_SUPPRESSED_FALSE); + $data['action']['notify_if_canceled'] = getRequest('notify_if_canceled', + ACTION_NOTIFY_IF_CANCELED_FALSE + ); } } else { @@ -563,6 +574,9 @@ if (hasRequest('form')) { $data['action']['pause_suppressed'] = getRequest('pause_suppressed', hasRequest('form_refresh') ? ACTION_PAUSE_SUPPRESSED_FALSE : ACTION_PAUSE_SUPPRESSED_TRUE ); + $data['action']['notify_if_canceled'] = getRequest('notify_if_canceled', + hasRequest('form_refresh') ? ACTION_NOTIFY_IF_CANCELED_FALSE : ACTION_NOTIFY_IF_CANCELED_TRUE + ); } } } diff --git a/ui/include/classes/api/services/CAction.php b/ui/include/classes/api/services/CAction.php index 93d81ad6cd0..7a673ca663a 100644 --- a/ui/include/classes/api/services/CAction.php +++ b/ui/include/classes/api/services/CAction.php @@ -2520,6 +2520,10 @@ class CAction extends CApiService { ['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_TRIGGERS], 'type' => API_OBJECTS, 'fields' => self::getOperationValidationRules(ACTION_UPDATE_OPERATION, EVENT_SOURCE_TRIGGERS)], ['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_SERVICE], 'type' => API_OBJECTS, 'fields' => self::getOperationValidationRules(ACTION_UPDATE_OPERATION, EVENT_SOURCE_SERVICE)], ['else' => true, 'type' => API_UNEXPECTED] + ]], + 'notify_if_canceled' => ['type' => API_MULTIPLE, 'rules' => [ + ['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_TRIGGERS], 'type' => API_INT32, 'in' => implode(',', [ACTION_NOTIFY_IF_CANCELED_FALSE, ACTION_NOTIFY_IF_CANCELED_TRUE])], + ['else' => true, 'type' => API_UNEXPECTED] ]] ]]; @@ -2561,7 +2565,9 @@ class CAction extends CApiService { } $db_actions = $this->get([ - 'output' => ['actionid', 'name', 'eventsource', 'status', 'esc_period', 'pause_suppressed'], + 'output' => ['actionid', 'name', 'eventsource', 'status', 'esc_period', 'pause_suppressed', + 'notify_if_canceled' + ], 'actionids' => array_column($actions, 'actionid'), 'editable' => true, 'preservekeys' => true @@ -2611,6 +2617,10 @@ class CAction extends CApiService { ['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_TRIGGERS], 'type' => API_OBJECTS, 'fields' => self::getOperationValidationRules(ACTION_UPDATE_OPERATION, EVENT_SOURCE_TRIGGERS)], ['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_SERVICE], 'type' => API_OBJECTS, 'fields' => self::getOperationValidationRules(ACTION_UPDATE_OPERATION, EVENT_SOURCE_SERVICE)], ['else' => true, 'type' => API_UNEXPECTED] + ]], + 'notify_if_canceled' => ['type' => API_MULTIPLE, 'rules' => [ + ['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_TRIGGERS], 'type' => API_INT32, 'in' => implode(',', [ACTION_NOTIFY_IF_CANCELED_FALSE, ACTION_NOTIFY_IF_CANCELED_TRUE])], + ['else' => true, 'type' => API_UNEXPECTED] ]] ]]; diff --git a/ui/include/classes/api/services/CScript.php b/ui/include/classes/api/services/CScript.php index 6dc9e6621b2..e18764f98ba 100644 --- a/ui/include/classes/api/services/CScript.php +++ b/ui/include/classes/api/services/CScript.php @@ -40,7 +40,9 @@ class CScript extends CApiService { /** * Fields from "actions" table. Used in get() validation and addRelatedObjects() when selecting action fields. */ - private $action_fields = ['actionid', 'name', 'eventsource', 'status', 'esc_period', 'pause_suppressed']; + private $action_fields = ['actionid', 'name', 'eventsource', 'status', 'esc_period', 'pause_suppressed', + 'notify_if_canceled' + ]; /** * This property, if filled out, will contain all hostrgroup ids diff --git a/ui/include/defines.inc.php b/ui/include/defines.inc.php index 533fd60dc50..7ee65edf872 100644 --- a/ui/include/defines.inc.php +++ b/ui/include/defines.inc.php @@ -22,7 +22,7 @@ define('ZABBIX_VERSION', '6.0.0alpha8'); define('ZABBIX_API_VERSION', '6.0.0'); define('ZABBIX_EXPORT_VERSION', '6.0'); -define('ZABBIX_DB_VERSION', 5050111); +define('ZABBIX_DB_VERSION', 5050112); define('DB_VERSION_SUPPORTED', 0); define('DB_VERSION_LOWER_THAN_MINIMUM', 1); @@ -737,6 +737,9 @@ define('ACTION_STATUS_DISABLED', 1); define('ACTION_PAUSE_SUPPRESSED_FALSE', 0); define('ACTION_PAUSE_SUPPRESSED_TRUE', 1); +define('ACTION_NOTIFY_IF_CANCELED_FALSE', 0); +define('ACTION_NOTIFY_IF_CANCELED_TRUE', 1); + define('OPERATION_TYPE_MESSAGE', 0); define('OPERATION_TYPE_COMMAND', 1); define('OPERATION_TYPE_HOST_ADD', 2); diff --git a/ui/include/schema.inc.php b/ui/include/schema.inc.php index 81803c63833..069f0cf11fd 100644 --- a/ui/include/schema.inc.php +++ b/ui/include/schema.inc.php @@ -1778,6 +1778,12 @@ return [ 'type' => DB::FIELD_TYPE_INT, 'length' => 10, 'default' => '1' + ], + 'notify_if_canceled' => [ + 'null' => false, + 'type' => DB::FIELD_TYPE_INT, + 'length' => 10, + 'default' => '1' ] ] ], diff --git a/ui/include/views/configuration.action.edit.php b/ui/include/views/configuration.action.edit.php index f30e6c01691..f0ff35e9a10 100644 --- a/ui/include/views/configuration.action.edit.php +++ b/ui/include/views/configuration.action.edit.php @@ -159,13 +159,6 @@ if (in_array($data['eventsource'], [EVENT_SOURCE_TRIGGERS, EVENT_SOURCE_INTERNAL ); } -if ($data['eventsource'] == EVENT_SOURCE_TRIGGERS) { - $operation_tab->addRow(_('Pause operations for suppressed problems'), - (new CCheckBox('pause_suppressed', ACTION_PAUSE_SUPPRESSED_TRUE)) - ->setChecked($data['action']['pause_suppressed'] == ACTION_PAUSE_SUPPRESSED_TRUE) - ); -} - // create operation table $operations_table = (new CTable()) ->setId('op-table') @@ -473,6 +466,18 @@ if ($data['eventsource'] == EVENT_SOURCE_TRIGGERS || $data['eventsource'] == EVE ); } +if ($data['eventsource'] == EVENT_SOURCE_TRIGGERS) { + $operation_tab + ->addRow(_('Pause operations for suppressed problems'), + (new CCheckBox('pause_suppressed', ACTION_PAUSE_SUPPRESSED_TRUE)) + ->setChecked($data['action']['pause_suppressed'] == ACTION_PAUSE_SUPPRESSED_TRUE) + ) + ->addRow(_('Notify about canceled escalations'), + (new CCheckBox('notify_if_canceled', ACTION_NOTIFY_IF_CANCELED_TRUE)) + ->setChecked($data['action']['notify_if_canceled'] == ACTION_NOTIFY_IF_CANCELED_TRUE) + ); +} + // Append tabs to form. $action_tabs = (new CTabView()) ->addTab('actionTab', _('Action'), $action_tab) diff --git a/ui/tests/integration/testEscalations.php b/ui/tests/integration/testEscalations.php index b3fdb092675..382d5f9a53d 100644 --- a/ui/tests/integration/testEscalations.php +++ b/ui/tests/integration/testEscalations.php @@ -505,7 +505,7 @@ class testEscalations extends CIntegrationTest { 'actionids' => [self::$trigger_actionid], 'sortfield' => 'alertid' ], 5, 2); - $esc_msg = 'NOTE: Escalation cancelled'; + $esc_msg = 'NOTE: Escalation canceled'; $this->assertArrayHasKey(1, $response['result']); $this->assertEquals(0, strncmp($esc_msg, $response['result'][1]['message'], strlen($esc_msg))); @@ -519,6 +519,57 @@ class testEscalations extends CIntegrationTest { $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); } /** |