mirror of
https://github.com/Cacti/plugin_thold.git
synced 2026-10-23 03:27:05 +09:00
* Guard maint maintenance-window checks against a missing maint functions file #858 corrected the maint functions include path but left three plugin_maint_check_cacti_host() calls guarded only by api_plugin_is_enabled('maint'). When maint is enabled but its functions file cannot be included (the include block now logs and continues rather than fataling), those calls hit an undefined function and fatal the poll. Add a function_exists('plugin_maint_check_cacti_host') guard to all three call sites (thold_check_threshold() and both the recovering- and down-device loops in thold_update_host_status()) so a missing maint include degrades gracefully, matching the guard other plugins use. Cover both maintenance-gated notification branches with a new MaintCheckGuardTest; add an html_split_string() test stub so the recovering-device path can be driven in the isolated unit process. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Let unexpected errors fail the maint-guard tests Drop the broad catch(Throwable) in the host-status test helper. A device inside a maintenance window is logged and the loop continues without the downstream notification work, so the call returns on its own; removing the catch means an unexpected error (such as a removed guard fataling on an undefined maint function) now fails the test instead of being swallowed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
986 lines
40 KiB
PHP
986 lines
40 KiB
PHP
<?php
|
|
/*
|
|
+-------------------------------------------------------------------------+
|
|
| Copyright (C) 2004-2026 The Cacti Group |
|
|
| |
|
|
| 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. |
|
|
+-------------------------------------------------------------------------+
|
|
| Cacti: The Complete RRDTool-based Graphing Solution |
|
|
+-------------------------------------------------------------------------+
|
|
| This code is designed, written, and maintained by the Cacti Group. See |
|
|
| about.php and/or the AUTHORS file for specific developer information. |
|
|
+-------------------------------------------------------------------------+
|
|
| http://www.cacti.net/ |
|
|
+-------------------------------------------------------------------------+
|
|
*/
|
|
|
|
/**
|
|
* Launches the Thold poller script (poller_thold.php) as a background
|
|
* process, logging a fatal error instead if the script file is
|
|
* missing. Registered as the 'poller_bottom' Cacti hook, invoked at
|
|
* the end of each Cacti poller cycle.
|
|
*
|
|
* @return void
|
|
*
|
|
* @global array $config Cacti global configuration array;
|
|
* used to build the poller script's
|
|
* path and command line.
|
|
* @global string $database_type Reserved/declared for parity with
|
|
* other functions in this file; not
|
|
* used directly here.
|
|
* @global string $database_default Reserved/declared for parity with
|
|
* other functions in this file; not
|
|
* used directly here.
|
|
* @global string $database_hostname Reserved/declared for parity with
|
|
* other functions in this file; not
|
|
* used directly here.
|
|
* @global string $database_username Reserved/declared for parity with
|
|
* other functions in this file; not
|
|
* used directly here.
|
|
* @global string $database_password Reserved/declared for parity with
|
|
* other functions in this file; not
|
|
* used directly here.
|
|
* @global int $database_port Reserved/declared for parity with
|
|
* other functions in this file; not
|
|
* used directly here.
|
|
* @global bool $database_ssl Reserved/declared for parity with
|
|
* other functions in this file; not
|
|
* used directly here.
|
|
*/
|
|
function thold_poller_bottom() {
|
|
global $config, $database_type, $database_default, $database_hostname;
|
|
global $database_username, $database_password, $database_port, $database_ssl;
|
|
|
|
$command_string = cacti_escapeshellcmd(read_config_option('path_php_binary'));
|
|
$file_path = $config['base_path'] . '/plugins/thold/poller_thold.php';
|
|
|
|
if (file_exists($file_path)) {
|
|
exec_background($command_string, $file_path);
|
|
} else {
|
|
cacti_log('FATAL: The Threshold Processing Script \'poller_thold.php\' is missing', false, 'THOLD');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Deletes plugin_thold_log entries older than the configured retention
|
|
* period (thold_log_storage days, defaulting to and persisting 31 if
|
|
* unset), and updates the last-change timestamp setting when any rows
|
|
* were actually removed.
|
|
*
|
|
* @return void
|
|
*/
|
|
function thold_cleanup_log() {
|
|
$daysToStoreLogs = read_config_option('thold_log_storage');
|
|
|
|
if (empty($daysToStoreLogs)) {
|
|
$daysToStoreLogs = 31;
|
|
set_config_option('thold_log_storage', '31');
|
|
}
|
|
|
|
$t = time() - (86400 * $daysToStoreLogs); // Delete Logs over a month old
|
|
|
|
db_execute_prepared('DELETE FROM plugin_thold_log
|
|
WHERE time < ?',
|
|
[$t]);
|
|
|
|
if (db_affected_rows() > 0) {
|
|
set_config_option('time_last_change_thold_log', time());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Cacti poller output-processing hook: intercepts newly collected RRD
|
|
* data source values, re-indexes them by data source id for threshold
|
|
* evaluation, and hands them off to the threshold-checking logic
|
|
* before/alongside the normal RRD update flow. Registered as a Cacti
|
|
* poller output hook.
|
|
*
|
|
* @param array &$rrd_update_array The newly collected poller output
|
|
* data, keyed by local_data_id.
|
|
*
|
|
* @return array The (possibly filtered/annotated) $rrd_update_array,
|
|
* for hook chaining.
|
|
*
|
|
* @global array $config Cacti global configuration array; used to
|
|
* locate library files to include.
|
|
* @global bool $debug Whether debug output is enabled.
|
|
*/
|
|
function thold_poller_output(&$rrd_update_array) {
|
|
global $config, $debug;
|
|
|
|
include_once($config['base_path'] . '/plugins/thold/includes/functions.php');
|
|
include_once($config['library_path'] . '/snmp.php');
|
|
|
|
$rrd_reindexed = [];
|
|
$rrd_time_reindexed = [];
|
|
$local_data_ids = '';
|
|
|
|
foreach ($rrd_update_array as $item) {
|
|
if (isset($item['times'][key($item['times'])])) {
|
|
$local_data_ids .= ($local_data_ids != '' ? ', ' : '') . $item['local_data_id'];
|
|
$rrd_reindexed[$item['local_data_id']] = $item['times'][key($item['times'])];
|
|
$rrd_time_reindexed[$item['local_data_id']] = key($item['times']);
|
|
}
|
|
}
|
|
|
|
if ($local_data_ids != '') {
|
|
if (read_config_option('thold_daemon_enable') == 'on') {
|
|
// array_chunk() takes the size of each chunk, not how many to make.
|
|
$rrd_update_array_chunks = array_chunk($rrd_update_array, 50, true);
|
|
|
|
foreach ($rrd_update_array_chunks as $rrd_update_array_chunk) {
|
|
$rrd_reindexed = [];
|
|
$rrd_time_reindexed = [];
|
|
$local_data_ids = '';
|
|
$thold_items = [];
|
|
|
|
foreach ($rrd_update_array_chunk as $item) {
|
|
if (isset($item['times'][key($item['times'])])) {
|
|
$local_data_ids .= ($local_data_ids != '' ? ', ' : '') . $item['local_data_id'];
|
|
|
|
$rrd_reindexed[$item['local_data_id']] = $item['times'][key($item['times'])];
|
|
$rrd_time_reindexed[$item['local_data_id']] = key($item['times']);
|
|
}
|
|
}
|
|
|
|
if ($local_data_ids != '') {
|
|
$thold_items = db_fetch_assoc("SELECT id, local_data_id, thread_id
|
|
FROM thold_data
|
|
WHERE thold_data.local_data_id IN ($local_data_ids)");
|
|
}
|
|
|
|
if (cacti_sizeof($thold_items)) {
|
|
/**
|
|
* cache required polling data. prefer bulk inserts for
|
|
* performance reasons - start with chunks of 1000 items
|
|
*/
|
|
$sql_max_inserts = 1000;
|
|
$thold_items = array_chunk($thold_items, $sql_max_inserts);
|
|
|
|
$sql_insert = 'INSERT INTO plugin_thold_daemon_data
|
|
(poller_id, id, thread_id, rrd_reindexed, rrd_time_reindexed) VALUES ';
|
|
|
|
foreach ($thold_items as $packet) {
|
|
$sql_values = '';
|
|
|
|
foreach ($packet as $thold_item) {
|
|
$sql_values .= ($sql_values != '' ? ', ' : '') . '(' . $config['poller_id'] . ', ' . $thold_item['id'] . ', ' . $thold_item['thread_id'] . ', ' . db_qstr(json_encode($rrd_reindexed[$thold_item['local_data_id']])) . ', ' . $rrd_time_reindexed[$thold_item['local_data_id']] . ')';
|
|
}
|
|
|
|
db_execute($sql_insert . $sql_values);
|
|
}
|
|
}
|
|
}
|
|
|
|
return $rrd_update_array;
|
|
}
|
|
} else {
|
|
return $rrd_update_array;
|
|
}
|
|
|
|
$tholds = db_fetch_assoc("SELECT td.id, td.name_cache AS thold_name,
|
|
td.local_graph_id, td.percent_ds, td.expression, td.upper_ds, td.data_type,
|
|
td.cdef, td.local_data_id, td.data_template_rrd_id, td.lastread,
|
|
UNIX_TIMESTAMP(td.lasttime) AS lasttime, td.oldvalue,
|
|
td.data_source_name AS name, dtr.data_source_type_id,
|
|
dtd.rrd_step, dtr.rrd_maximum, dtr.rrd_heartbeat
|
|
FROM thold_data AS td
|
|
LEFT JOIN data_template_rrd AS dtr
|
|
ON dtr.id = td.data_template_rrd_id
|
|
LEFT JOIN data_template_data AS dtd
|
|
ON dtd.local_data_id = td.local_data_id
|
|
WHERE dtr.data_source_name != ''
|
|
AND td.local_data_id IN($local_data_ids)");
|
|
|
|
if (cacti_sizeof($tholds)) {
|
|
$sql = [];
|
|
$status_sql = [];
|
|
|
|
foreach ($tholds as $thold_data) {
|
|
thold_debug("Checking Threshold: Name: '" . $thold_data['thold_name'] . "', Graph: '" . $thold_data['local_graph_id'] . "'");
|
|
|
|
$item = [];
|
|
$currenttime = 0;
|
|
$postvalue = thold_get_currentval($thold_data, $rrd_reindexed, $rrd_time_reindexed, $item, $currenttime);
|
|
$currentval = $postvalue;
|
|
|
|
switch ($thold_data['data_type']) {
|
|
case 0:
|
|
break;
|
|
case 1:
|
|
if ($thold_data['cdef'] != 0) {
|
|
$currentval = thold_build_cdef($thold_data['cdef'], $postvalue, $thold_data['local_data_id'], $thold_data['data_template_rrd_id']);
|
|
}
|
|
|
|
break;
|
|
case 2:
|
|
if ($thold_data['percent_ds'] != '') {
|
|
$currentval = thold_calculate_percent($thold_data, $postvalue, $rrd_reindexed);
|
|
}
|
|
|
|
break;
|
|
case 3:
|
|
if ($thold_data['expression'] != '') {
|
|
$currentval = thold_calculate_expression($thold_data, $postvalue, $rrd_reindexed, $rrd_time_reindexed);
|
|
}
|
|
|
|
break;
|
|
case 4:
|
|
if ($thold_data['upper_ds'] != '') {
|
|
$currentval = thold_calculate_lower_upper($thold_data, $postvalue, $rrd_reindexed);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (!is_numeric($currentval)) {
|
|
if (read_config_option('thold_consider_unknown_zero') == 'on') {
|
|
$normalized = strtolower($currentval);
|
|
|
|
if ($normalized == 'u' || $normalized == 'nan' || $normalized == '') {
|
|
// Fail closed: an unavailable sample must not be persisted as a
|
|
// manufactured zero, or thold_check_threshold()'s unavailable-sample
|
|
// guard never sees it and can alert/recover on the fabricated value.
|
|
thold_debug('Threshold: ' . $thold_data['thold_name'] . ' unknown value would have been treated as zero; preserving unavailable state instead', 'thold');
|
|
|
|
if (read_config_option('thold_log_unknown_to_zero') == 'on') {
|
|
cacti_log('NOTE: Threshold \'' . $thold_data['thold_name'] . '\' unknown value would have been treated as zero; preserving unavailable state instead', true, 'THOLD');
|
|
}
|
|
}
|
|
}
|
|
|
|
$currentval = '';
|
|
}
|
|
|
|
$sample_rows = thold_polling_sample_row($thold_data, $item, $currentval, $currenttime);
|
|
|
|
if ($sample_rows['sample_row'] !== null) {
|
|
$sql[] = $sample_rows['sample_row'];
|
|
} elseif ($sample_rows['status_row'] !== null) {
|
|
$status_sql[] = $sample_rows['status_row'];
|
|
}
|
|
}
|
|
|
|
if (cacti_sizeof($sql)) {
|
|
foreach (array_chunk($sql, 400) as $chunk) {
|
|
$placeholders = implode(', ', array_fill(0, cacti_sizeof($chunk), '(?, ?, ?, FROM_UNIXTIME(?), ?)'));
|
|
$params = [];
|
|
|
|
foreach ($chunk as $row) {
|
|
$params[] = $row['id'];
|
|
$params[] = $row['tcheck'];
|
|
$params[] = $row['lastread'];
|
|
$params[] = $row['lasttime'];
|
|
$params[] = $row['oldvalue'];
|
|
}
|
|
|
|
db_execute_prepared('INSERT INTO thold_data
|
|
(id, tcheck, lastread, lasttime, oldvalue)
|
|
VALUES ' . $placeholders . '
|
|
ON DUPLICATE KEY UPDATE
|
|
tcheck = VALUES(tcheck),
|
|
lastread = VALUES(lastread),
|
|
lasttime = VALUES(lasttime),
|
|
oldvalue = VALUES(oldvalue)',
|
|
$params);
|
|
}
|
|
|
|
}
|
|
|
|
if (cacti_sizeof($status_sql)) {
|
|
foreach (array_chunk($status_sql, 400) as $chunk) {
|
|
$placeholders = implode(', ', array_fill(0, cacti_sizeof($chunk), '(?, ?, ?)'));
|
|
$params = [];
|
|
|
|
foreach ($chunk as $row) {
|
|
$params[] = $row['id'];
|
|
$params[] = $row['tcheck'];
|
|
$params[] = $row['lastread'];
|
|
}
|
|
|
|
db_execute_prepared('INSERT INTO thold_data
|
|
(id, tcheck, lastread)
|
|
VALUES ' . $placeholders . '
|
|
ON DUPLICATE KEY UPDATE
|
|
tcheck = VALUES(tcheck),
|
|
lastread = VALUES(lastread)',
|
|
$params);
|
|
}
|
|
}
|
|
|
|
thold_polling_cleanup(cacti_sizeof($sql) || cacti_sizeof($status_sql));
|
|
}
|
|
|
|
return $rrd_update_array;
|
|
}
|
|
|
|
/**
|
|
* Evaluates every configured threshold against its data source's
|
|
* current/historical values (fetching remote-poller data directly from
|
|
* the remote database when remote storage is configured), triggering
|
|
* notifications/alerts for thresholds that have tripped or recovered.
|
|
* Invoked once per poller cycle from the main threshold-checking flow.
|
|
*
|
|
* @return int The total number of thresholds evaluated.
|
|
*
|
|
* @global array $config Cacti global configuration array; used to
|
|
* locate library files to include.
|
|
*/
|
|
function thold_check_all_thresholds() {
|
|
global $config;
|
|
|
|
include($config['base_path'] . '/plugins/thold/includes/arrays.php');
|
|
include_once($config['base_path'] . '/plugins/thold/includes/functions.php');
|
|
include_once($config['base_path'] . '/lib/time.php');
|
|
|
|
if (read_config_option('remote_storage_method') == 1) {
|
|
if ($config['poller_id'] == 1) {
|
|
$sql_query = "SELECT td.*, h.hostname,
|
|
h.description, h.site_id, h.location, h.notes AS dnotes, h.snmp_engine_id
|
|
FROM thold_data AS td
|
|
LEFT JOIN host AS h
|
|
ON h.id = td.host_id
|
|
LEFT JOIN data_template_rrd AS dtr
|
|
ON dtr.id = td.data_template_rrd_id
|
|
WHERE thold_per_enabled = 'on'
|
|
AND (
|
|
thold_template_id = 0
|
|
OR (
|
|
thold_template_id > 0
|
|
AND (
|
|
template_enabled != 'on' OR (template_enabled = 'on' AND thold_enabled = 'on')
|
|
)
|
|
)
|
|
)
|
|
AND (h.poller_id = 1 OR h.poller_id IS NULL)
|
|
AND td.tcheck = 1
|
|
AND h.status = 3";
|
|
} else {
|
|
$sql_query = 'SELECT td.*, h.hostname,
|
|
h.description, h.site_id, h.location, h.notes AS dnotes, h.snmp_engine_id
|
|
FROM thold_data AS td
|
|
LEFT JOIN host AS h
|
|
ON h.id = td.host_id
|
|
LEFT JOIN data_template_rrd AS dtr
|
|
ON dtr.id = td.data_template_rrd_id
|
|
WHERE h.poller_id = ' . $config['poller_id'] . "
|
|
AND thold_per_enabled = 'on'
|
|
AND (
|
|
thold_template_id = 0
|
|
OR (
|
|
thold_template_id > 0
|
|
AND (
|
|
template_enabled != 'on' OR (template_enabled = 'on' AND thold_enabled = 'on')
|
|
)
|
|
)
|
|
)
|
|
AND td.tcheck = 1
|
|
AND h.status = 3";
|
|
}
|
|
} else {
|
|
$sql_query = "SELECT td.*, h.hostname,
|
|
h.description, h.site_id, h.location, h.notes AS dnotes, h.snmp_engine_id
|
|
FROM thold_data AS td
|
|
LEFT JOIN data_template_rrd AS dtr
|
|
ON dtr.id = td.data_template_rrd_id
|
|
LEFT JOIN host as h
|
|
ON td.host_id = h.id
|
|
WHERE thold_per_enabled = 'on'
|
|
AND (
|
|
thold_template_id = 0
|
|
OR (
|
|
thold_template_id > 0
|
|
AND (
|
|
template_enabled != 'on' OR (template_enabled = 'on' AND thold_enabled = 'on')
|
|
)
|
|
)
|
|
)
|
|
AND td.tcheck = 1
|
|
AND h.status = 3";
|
|
}
|
|
|
|
$tholds = api_plugin_hook_function('thold_get_live_hosts', db_fetch_assoc($sql_query));
|
|
|
|
$total_tholds = sizeof($tholds);
|
|
|
|
$checked = [];
|
|
|
|
foreach ($tholds as $thold) {
|
|
thold_check_threshold($thold);
|
|
|
|
$checked[] = (int) $thold['id'];
|
|
}
|
|
|
|
/*
|
|
* Clear the dirty flag on what was evaluated, and nothing else. Clearing
|
|
* by poller, or across the whole table, also cleared the thresholds whose
|
|
* data arrived after the select above, so those readings were dropped
|
|
* without ever being checked. The select already scopes to this poller,
|
|
* so the identifiers carry that scoping with them.
|
|
*/
|
|
if (cacti_sizeof($checked)) {
|
|
$placeholders = implode(', ', array_fill(0, cacti_sizeof($checked), '?'));
|
|
|
|
db_execute_prepared('UPDATE thold_data
|
|
SET tcheck = 0
|
|
WHERE id IN (' . $placeholders . ')',
|
|
$checked);
|
|
}
|
|
|
|
return $total_tholds;
|
|
}
|
|
|
|
/**
|
|
* Checks each monitored host's reachability status (including hosts
|
|
* managed by the Maint plugin, when enabled) and records/clears dead-
|
|
* host notification tracking rows, when the alert_deadnotify setting
|
|
* is enabled; a no-op otherwise.
|
|
*
|
|
* @return int|null 0 immediately if dead-host notifications are
|
|
* disabled; otherwise no explicit return value
|
|
* (null).
|
|
*
|
|
* @global array $config Cacti global configuration array; used to
|
|
* locate library files to include.
|
|
*/
|
|
function thold_update_host_status() {
|
|
global $config;
|
|
|
|
// Return if we aren't set to notify
|
|
$deadnotify = (read_config_option('alert_deadnotify') == 'on');
|
|
|
|
if (!$deadnotify) {
|
|
return 0;
|
|
}
|
|
|
|
include_once($config['base_path'] . '/plugins/thold/includes/functions.php');
|
|
include_once($config['library_path'] . '/snmp.php');
|
|
|
|
if (api_plugin_is_enabled('maint')) {
|
|
if (file_exists($config['base_path'] . '/plugins/maint/functions.php')) {
|
|
require_once($config['base_path'] . '/plugins/maint/functions.php');
|
|
} else if (file_exists($config['base_path'] . '/plugins/maint/includes/functions.php')) {
|
|
require_once($config['base_path'] . '/plugins/maint/includes/functions.php');
|
|
} else {
|
|
cacti_log('ERROR: cannot include maint functions', false, 'THOLD');
|
|
}
|
|
}
|
|
|
|
$ping_failure_count = read_config_option('ping_failure_count');
|
|
|
|
$queue = read_config_option('thold_notification_queue');
|
|
|
|
// Lets find hosts that were down, but are now back up
|
|
if (read_config_option('remote_storage_method') == 1) {
|
|
$failed = db_fetch_assoc_prepared('SELECT *
|
|
FROM plugin_thold_host_failed
|
|
WHERE poller_id = ?',
|
|
[$config['poller_id']]);
|
|
} else {
|
|
$failed = db_fetch_assoc('SELECT *
|
|
FROM plugin_thold_host_failed');
|
|
}
|
|
|
|
if (cacti_sizeof($failed)) {
|
|
foreach ($failed as $fh) {
|
|
$alert_email = read_config_option('alert_email');
|
|
|
|
$host = db_fetch_row_prepared('SELECT *
|
|
FROM host
|
|
WHERE id = ?',
|
|
[$fh['host_id']]);
|
|
|
|
$notify_list_id = 0;
|
|
|
|
if (!sizeof($host)) {
|
|
db_execute_prepared('DELETE
|
|
FROM plugin_thold_host_failed
|
|
WHERE host_id = ?',
|
|
[$fh['host_id']]);
|
|
|
|
set_config_option('time_last_change_thold_device', time());
|
|
} elseif ($host['status'] == HOST_UP) {
|
|
$snmp_system = '';
|
|
$snmp_hostname = '';
|
|
$snmp_location = '';
|
|
$snmp_contact = '';
|
|
$snmp_uptime = '';
|
|
$uptimelong = '';
|
|
$downtimemsg = '';
|
|
|
|
if (($host['snmp_community'] == '' && $host['snmp_username'] == '') || $host['snmp_version'] == 0) {
|
|
// SNMP not in use
|
|
$snmp_system = __('SNMP not in use', 'thold');
|
|
} else {
|
|
$snmp_system = cacti_snmp_get($host['hostname'], $host['snmp_community'], '.1.3.6.1.2.1.1.1.0', $host['snmp_version'], $host['snmp_username'], $host['snmp_password'], $host['snmp_auth_protocol'], $host['snmp_priv_passphrase'], $host['snmp_priv_protocol'], $host['snmp_context'], $host['snmp_port'], $host['snmp_timeout'], read_config_option('snmp_retries'), SNMP_WEBUI);
|
|
|
|
if (substr_count($snmp_system, '00:')) {
|
|
$snmp_system = str_replace('00:', '', $snmp_system);
|
|
$snmp_system = str_replace(':', ' ', $snmp_system);
|
|
}
|
|
|
|
if ($snmp_system != '') {
|
|
$snmp_uptime = cacti_snmp_get($host['hostname'], $host['snmp_community'], '.1.3.6.1.6.3.10.2.1.3.0', $host['snmp_version'], $host['snmp_username'], $host['snmp_password'], $host['snmp_auth_protocol'], $host['snmp_priv_passphrase'], $host['snmp_priv_protocol'], $host['snmp_context'], $host['snmp_port'], $host['snmp_timeout'], read_config_option('snmp_retries'), SNMP_WEBUI);
|
|
|
|
if (!is_numeric($snmp_uptime)) {
|
|
$snmp_uptime = cacti_snmp_get($host['hostname'], $host['snmp_community'], '.1.3.6.1.2.1.1.3.0', $host['snmp_version'], $host['snmp_username'], $host['snmp_password'], $host['snmp_auth_protocol'], $host['snmp_priv_passphrase'], $host['snmp_priv_protocol'], $host['snmp_context'], $host['snmp_port'], $host['snmp_timeout'], read_config_option('snmp_retries'), SNMP_WEBUI);
|
|
} else {
|
|
$snmp_uptime *= 100;
|
|
}
|
|
|
|
$snmp_hostname = cacti_snmp_get($host['hostname'], $host['snmp_community'], '.1.3.6.1.2.1.1.5.0', $host['snmp_version'], $host['snmp_username'], $host['snmp_password'], $host['snmp_auth_protocol'], $host['snmp_priv_passphrase'], $host['snmp_priv_protocol'], $host['snmp_context'], $host['snmp_port'], $host['snmp_timeout'], read_config_option('snmp_retries'), SNMP_WEBUI);
|
|
|
|
$snmp_location = cacti_snmp_get($host['hostname'], $host['snmp_community'], '.1.3.6.1.2.1.1.6.0', $host['snmp_version'], $host['snmp_username'], $host['snmp_password'], $host['snmp_auth_protocol'], $host['snmp_priv_passphrase'], $host['snmp_priv_protocol'], $host['snmp_context'], $host['snmp_port'], $host['snmp_timeout'], read_config_option('snmp_retries'), SNMP_WEBUI);
|
|
|
|
$snmp_contact = cacti_snmp_get($host['hostname'], $host['snmp_community'], '.1.3.6.1.2.1.1.4.0', $host['snmp_version'], $host['snmp_username'], $host['snmp_password'], $host['snmp_auth_protocol'], $host['snmp_priv_passphrase'], $host['snmp_priv_protocol'], $host['snmp_context'], $host['snmp_port'], $host['snmp_timeout'], read_config_option('snmp_retries'), SNMP_WEBUI);
|
|
|
|
if (is_numeric($snmp_uptime)) {
|
|
$days = intval($snmp_uptime / (60 * 60 * 24 * 100));
|
|
$remainder = $snmp_uptime % (60 * 60 * 24 * 100);
|
|
$hours = intval($remainder / (60 * 60 * 100));
|
|
$remainder = $remainder % (60 * 60 * 100);
|
|
$minutes = intval($remainder / (60 * 100));
|
|
$uptimelong = $days . 'd ' . $hours . 'h ' . $minutes . 'm';
|
|
} else {
|
|
$days = '0';
|
|
$remainder = '0';
|
|
$hours = '0';
|
|
$remainder = '0';
|
|
$minutes = '0';
|
|
$uptimelong = $days . 'd ' . $hours . 'h ' . $minutes . 'm';
|
|
}
|
|
}
|
|
}
|
|
|
|
if (strtotime($host['status_fail_date']) > 192800) {
|
|
$downtime = time() - strtotime($host['status_fail_date']);
|
|
$downtime_days = floor($downtime / 86400);
|
|
$downtime_hours = floor(($downtime - ($downtime_days * 86400)) / 3600);
|
|
$downtime_minutes = floor(($downtime - ($downtime_days * 86400) - ($downtime_hours * 3600)) / 60);
|
|
$downtime_seconds = $downtime - ($downtime_days * 86400) - ($downtime_hours * 3600) - ($downtime_minutes * 60);
|
|
|
|
if ($downtime_days > 0) {
|
|
$downtimemsg = $downtime_days . 'd ' . $downtime_hours . 'h ' . $downtime_minutes . 'm ' . $downtime_seconds . 's ';
|
|
} elseif ($downtime_hours > 0) {
|
|
$downtimemsg = $downtime_hours . 'h ' . $downtime_minutes . 'm ' . $downtime_seconds . 's';
|
|
} elseif ($downtime_minutes > 0) {
|
|
$downtimemsg = $downtime_minutes . 'm ' . $downtime_seconds . 's';
|
|
} else {
|
|
$downtimemsg = $downtime_seconds . 's ';
|
|
}
|
|
} else {
|
|
$downtimemsg = __('N/A', 'thold');
|
|
}
|
|
|
|
$subject = read_config_option('thold_up_subject');
|
|
|
|
if ($subject == '') {
|
|
$subject = __('Devices Notice: <DESCRIPTION> (<HOSTNAME>) returned from DOWN state', 'thold');
|
|
}
|
|
|
|
$site = db_fetch_cell_prepared('SELECT name FROM sites WHERE id = ?', [$host['site_id']]);
|
|
|
|
if ($site == '') {
|
|
$site = 'Unspecified';
|
|
}
|
|
|
|
$subject = thold_str_replace('<HOSTNAME>', $host['hostname'], $subject);
|
|
$subject = thold_str_replace('<DESCRIPTION>', $host['description'], $subject);
|
|
$subject = thold_str_replace('<SITE>', $site, $subject);
|
|
$subject = thold_str_replace('<LOCATION>', $host['location'], $subject);
|
|
$subject = thold_str_replace('<DOWN/UP>', 'UP', $subject);
|
|
$subject = thold_str_replace('<DOWNTIME>', $downtimemsg, $subject);
|
|
$subject = thold_str_replace('<NOTES>', $host['notes'], $subject);
|
|
$subject = strip_tags($subject);
|
|
|
|
$msg = read_config_option('thold_up_text');
|
|
|
|
if ($msg == '') {
|
|
$msg = __('<br>System <DESCRIPTION> (<HOSTNAME>) status: <DOWN/UP><br><br>Site: <SITE><br>Location: <LOCATION><br>Current ping response: <CUR_TIME> ms<br>Average system response : <AVG_TIME> ms<br>System availability: <AVAILABILITY><br>Total Checks Since Clear: <TOT_POLL><br>Total Failed Checks: <FAIL_POLL><br>Last Date Checked UP: <LAST_FAIL><br>Devices Previously DOWN for: <DOWNTIME><br><br>SNMP Info:<br>Name - <SNMP_HOSTNAME><br>Location - <SNMP_LOCATION><br>Uptime - <UPTIMETEXT> (<UPTIME> ms)<br>System - <SNMP_SYSTEM><br><br>NOTE: <NOTES>', 'thold');
|
|
}
|
|
|
|
$msg = thold_str_replace('<SUBJECT>', $subject, $msg);
|
|
$msg = thold_str_replace('<HOSTNAME>', $host['hostname'], $msg);
|
|
$msg = thold_str_replace('<HOST_ID>', $host['id'], $msg);
|
|
$msg = thold_str_replace('<DESCRIPTION>', $host['description'], $msg);
|
|
$msg = thold_str_replace('<SITE>', $site, $msg);
|
|
$msg = thold_str_replace('<LOCATION>', $host['location'], $msg);
|
|
$msg = thold_str_replace('<UPTIME>', $snmp_uptime, $msg);
|
|
$msg = thold_str_replace('<UPTIMETEXT>', $uptimelong, $msg);
|
|
|
|
$msg = thold_str_replace('<TIME>', time(), $msg);
|
|
$msg = thold_str_replace('<DATE>', date(CACTI_DATE_TIME_FORMAT), $msg);
|
|
$msg = thold_str_replace('<DATE_RFC822>', date(DATE_RFC822), $msg);
|
|
|
|
$msg = thold_str_replace('<DOWNTIME>', $downtimemsg, $msg);
|
|
$msg = thold_str_replace('<MESSAGE>', '', $msg);
|
|
$msg = thold_str_replace('<DOWN/UP>', 'UP', $msg);
|
|
|
|
$msg = thold_str_replace('<SNMP_HOSTNAME>', $snmp_hostname, $msg);
|
|
$msg = thold_str_replace('<SNMP_LOCATION>', $snmp_location, $msg);
|
|
$msg = thold_str_replace('<SNMP_CONTACT>', $snmp_contact, $msg);
|
|
$msg = thold_str_replace('<SNMP_SYSTEM>', html_split_string($snmp_system), $msg);
|
|
$msg = thold_str_replace('<LAST_FAIL>', $host['status_fail_date'], $msg);
|
|
$msg = thold_str_replace('<AVAILABILITY>', number_format_i18n(($host['availability']), 2) . ' %', $msg);
|
|
$msg = thold_str_replace('<TOT_POLL>', number_format_i18n($host['total_polls']), $msg);
|
|
$msg = thold_str_replace('<FAIL_POLL>', number_format_i18n($host['failed_polls']), $msg);
|
|
$msg = thold_str_replace('<CUR_TIME>', number_format_i18n(($host['cur_time']), 2), $msg);
|
|
$msg = thold_str_replace('<AVG_TIME>', number_format_i18n(($host['avg_time']), 2), $msg);
|
|
$msg = thold_str_replace('<NOTES>', $host['notes'], $msg);
|
|
$msg = thold_str_replace("\n", '<br>', $msg);
|
|
|
|
if (api_plugin_is_enabled('maint') && function_exists('plugin_maint_check_cacti_host') && plugin_maint_check_cacti_host($host['id'])) {
|
|
cacti_log('WARNING: Device[' . $host['id'] . '] Hostname[' . $host['hostname'] . '] is recovering! Only logging, maint device', true, 'THOLD');
|
|
} else {
|
|
switch ($host['thold_send_email']) {
|
|
case '0': // Disabled
|
|
$alert_email = '';
|
|
|
|
break;
|
|
case '1': // Global List
|
|
break;
|
|
case '2': // Devices List Only
|
|
$alert_email = get_thold_notification_emails($host['thold_host_email']);
|
|
$notify_list_id = $host['thold_host_email'];
|
|
|
|
break;
|
|
case '3': // Global and Devices List
|
|
$alert_email = $alert_email . ',' . get_thold_notification_emails($host['thold_host_email']);
|
|
$notify_list_id = $host['thold_host_email'];
|
|
|
|
break;
|
|
}
|
|
|
|
api_plugin_hook_function(
|
|
'thold_device_recovering',
|
|
[
|
|
'device' => $host,
|
|
'subject' => $subject,
|
|
'message' => $msg,
|
|
'email' => $alert_email
|
|
]
|
|
);
|
|
|
|
cacti_log('WARNING: Device[' . $host['id'] . '] Hostname[' . $host['hostname'] . '] is recovering!', true, 'THOLD');
|
|
|
|
if ($alert_email == '' && $host['thold_send_email'] > 0) {
|
|
cacti_log('WARNING: Device[' . $host['id'] . '] Hostname[' . $host['hostname'] . '] can not send a Device recovering email for \'' . $host['description'] . '\' since the \'Alert Email\' setting is not set for Device!', true, 'THOLD');
|
|
} elseif ($host['thold_send_email'] == '0') {
|
|
cacti_log('NOTE: Device[' . $host['id'] . '] Hostname[' . $host['hostname'] . '] did not send a Device recovering email for \'' . $host['description'] . '\', disabled per Device setting!', true, 'THOLD');
|
|
} elseif ($alert_email != '') {
|
|
thold_mail($alert_email, '', '', $subject, $msg, '', '', $notify_list_id, $host, '', 7, 'thold_uhost_mail');
|
|
}
|
|
|
|
$command = read_config_option('thold_device_command');
|
|
|
|
if ($command != '') {
|
|
thold_putenv('THOLD_SUBJECT=' . $subject, true);
|
|
thold_putenv('THOLD_HOSTNAME=' . $host['hostname']);
|
|
thold_putenv('THOLD_HOST_ID=' . $host['id']);
|
|
thold_putenv('THOLD_DESCRIPTION=' . $host['description']);
|
|
thold_putenv('THOLD_SITE=' . $site);
|
|
thold_putenv('THOLD_LOCATION=' . $host['location']);
|
|
thold_putenv('THOLD_TIME=' . time());
|
|
thold_putenv('THOLD_DATE=' . date(CACTI_DATE_TIME_FORMAT));
|
|
thold_putenv('THOLD_DATE_RFC822=' . date(DATE_RFC822));
|
|
|
|
thold_putenv('THOLD_UPTIME=' . $snmp_uptime);
|
|
thold_putenv('THOLD_UPTIMETEXT=' . $uptimelong);
|
|
thold_putenv('THOLD_DOWNTIME=' . $downtimemsg);
|
|
thold_putenv('THOLD_MESSAGE=' . '');
|
|
thold_putenv('THOLD_DOWNUP=' . 'UP');
|
|
|
|
thold_putenv('THOLD_SNMP_HOSTNAME=' . $snmp_hostname);
|
|
thold_putenv('THOLD_SNMP_LOCATION=' . $snmp_location);
|
|
thold_putenv('THOLD_SNMP_CONTACT=' . $snmp_contact);
|
|
thold_putenv('THOLD_SNMP_SYSTEM=' . $snmp_system);
|
|
thold_putenv('THOLD_LAST_FAIL=' . $host['status_fail_date']);
|
|
thold_putenv('THOLD_AVAILABILITY=' . $host['availability']);
|
|
thold_putenv('THOLD_TOT_POLL=' . $host['total_polls']);
|
|
thold_putenv('THOLD_FAIL_POLL=' . $host['failed_polls']);
|
|
thold_putenv('THOLD_CUR_TIME=' . $host['cur_time']);
|
|
thold_putenv('THOLD_AVG_TIME=' . $host['avg_time']);
|
|
$environment = thold_putenv('THOLD_NOTES=' . $host['notes']);
|
|
|
|
if (file_exists($command) && is_executable($command)) {
|
|
$output = [];
|
|
$return = 0;
|
|
|
|
if ($queue == '') {
|
|
exec($command, $output, $return);
|
|
|
|
cacti_log('Device Up Command for Device[' . $host['id'] . '] Command[' . $command . '] ExitStatus[' . $return . '] Output[' . implode(' ', $output) . ']', false, 'THOLD');
|
|
} else {
|
|
$data = [
|
|
'command' => $command,
|
|
'data' => $host,
|
|
'environment' => $environment
|
|
];
|
|
|
|
thold_notification_add('thold_uhost_cmd', $data, 'id', $notify_list_id, $host);
|
|
}
|
|
} else {
|
|
cacti_log('WARNING: Device Up Command for Device[' . $host['id'] . '] Command[' . $command . '] Is either Not found or Not executable!', false, 'THOLD');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Lets find hosts that are down
|
|
if (read_config_option('remote_storage_method') == 1) {
|
|
$hosts = db_fetch_assoc_prepared('SELECT *
|
|
FROM host
|
|
WHERE disabled = ""
|
|
AND availability_method > 0
|
|
AND status = ?
|
|
AND status_event_count = IF(thold_failure_count > 0, thold_failure_count, ?)
|
|
AND poller_id = ?',
|
|
[HOST_DOWN, $ping_failure_count, $config['poller_id']]);
|
|
} else {
|
|
$hosts = db_fetch_assoc_prepared('SELECT *
|
|
FROM host
|
|
WHERE disabled = ""
|
|
AND availability_method > 0
|
|
AND status = ?
|
|
AND status_event_count = IF(thold_failure_count > 0, thold_failure_count, ?)',
|
|
[HOST_DOWN, $ping_failure_count]);
|
|
}
|
|
|
|
$total_hosts = cacti_sizeof($hosts);
|
|
|
|
if ($total_hosts) {
|
|
foreach ($hosts as $host) {
|
|
$notify_list_id = 0;
|
|
|
|
$alert_email = read_config_option('alert_email');
|
|
|
|
if (api_plugin_is_enabled('maint') && function_exists('plugin_maint_check_cacti_host') && plugin_maint_check_cacti_host($host['id'])) {
|
|
cacti_log('WARNING: Device[' . $host['id'] . '] Hostname[' . $host['hostname'] . '] is DOWN. Only logging, maint device', true, 'THOLD');
|
|
} else {
|
|
if (strtotime($host['status_fail_date']) > 192800 || strtotime($host['status_rec_date']) > 192800) {
|
|
$down_sec = db_fetch_cell_prepared('SELECT unix_timestamp(status_rec_date)-unix_timestamp(status_fail_date)
|
|
FROM host WHERE id = ?',
|
|
[$host['id']]);
|
|
|
|
$days = intval($down_sec / (60 * 60 * 24));
|
|
$remainder = $down_sec % (60 * 60 * 24);
|
|
$hours = intval($remainder / (60 * 60));
|
|
$remainder = $remainder % (60 * 60);
|
|
$minutes = intval($remainder / (60));
|
|
$last_state_duration = $days . 'd ' . $hours . 'h ' . $minutes . 'm';
|
|
} else {
|
|
$last_state_duration = __('N/A', 'thold');
|
|
}
|
|
|
|
$subject = read_config_option('thold_down_subject');
|
|
|
|
if ($subject == '') {
|
|
$subject = __('Devices Error: <DESCRIPTION> (<HOSTNAME>) is DOWN', 'thold');
|
|
}
|
|
|
|
$site = db_fetch_cell_prepared('SELECT name FROM sites WHERE id = ?', [$host['site_id']]);
|
|
|
|
if ($site == '') {
|
|
$site = 'Unspecified';
|
|
}
|
|
|
|
$subject = thold_str_replace('<HOSTNAME>', $host['hostname'], $subject);
|
|
$subject = thold_str_replace('<DESCRIPTION>', $host['description'], $subject);
|
|
$subject = thold_str_replace('<SITE>', $site, $subject);
|
|
$subject = thold_str_replace('<LOCATION>', $host['location'], $subject);
|
|
$subject = thold_str_replace('<DOWN/UP>', __('DOWN', 'thold'), $subject);
|
|
$subject = thold_str_replace('<DOWNTIME>', $last_state_duration, $subject);
|
|
$subject = thold_str_replace('<NOTES>', $host['notes'], $subject);
|
|
$subject = strip_tags($subject);
|
|
|
|
$msg = read_config_option('thold_down_text');
|
|
|
|
if ($msg == '') {
|
|
$msg = __('System Error : <DESCRIPTION> (<HOSTNAME>) is <DOWN/UP><br>Site: <SITE><br>Location: <LOCATION><br>Reason: <MESSAGE><br><br>Average system response : <AVG_TIME> ms<br>System availability: <AVAILABILITY><br>Total Checks Since Clear: <TOT_POLL><br>Total Failed Checks: <FAIL_POLL><br>Last Date Checked DOWN : <LAST_FAIL><br>Devices Previously UP for: <DOWNTIME><br>NOTE: <NOTES>', 'thold');
|
|
}
|
|
|
|
$msg = thold_str_replace('<SUBJECT>', $subject, $msg);
|
|
$msg = thold_str_replace('<HOSTNAME>', $host['hostname'], $msg);
|
|
$msg = thold_str_replace('<HOST_ID>', $host['id'], $msg);
|
|
$msg = thold_str_replace('<DESCRIPTION>', $host['description'], $msg);
|
|
$msg = thold_str_replace('<SITE>', $site, $msg);
|
|
$msg = thold_str_replace('<LOCATION>', $host['location'], $msg);
|
|
$msg = thold_str_replace('<UPTIME>', '', $msg);
|
|
$msg = thold_str_replace('<DOWNTIME>', $last_state_duration, $msg);
|
|
|
|
$msg = thold_str_replace('<TIME>', time(), $msg);
|
|
$msg = thold_str_replace('<DATE>', date(CACTI_DATE_TIME_FORMAT), $msg);
|
|
$msg = thold_str_replace('<DATE_RFC822>', date(DATE_RFC822), $msg);
|
|
|
|
$msg = thold_str_replace('<MESSAGE>', $host['status_last_error'], $msg);
|
|
$msg = thold_str_replace('<DOWN/UP>', __('DOWN', 'thold'), $msg);
|
|
$msg = thold_str_replace('<SNMP_HOSTNAME>', '', $msg);
|
|
$msg = thold_str_replace('<SNMP_LOCATION>', '', $msg);
|
|
$msg = thold_str_replace('<SNMP_CONTACT>', '', $msg);
|
|
$msg = thold_str_replace('<SNMP_SYSTEM>', '', $msg);
|
|
$msg = thold_str_replace('<LAST_FAIL>', $host['status_fail_date'], $msg);
|
|
$msg = thold_str_replace('<AVAILABILITY>', round(($host['availability']), 2) . ' %', $msg);
|
|
$msg = thold_str_replace('<CUR_TIME>', round(($host['cur_time']), 2), $msg);
|
|
$msg = thold_str_replace('<TOT_POLL>', $host['total_polls'], $msg);
|
|
$msg = thold_str_replace('<FAIL_POLL>', $host['failed_polls'], $msg);
|
|
$msg = thold_str_replace('<AVG_TIME>', round(($host['avg_time']), 2), $msg);
|
|
$msg = thold_str_replace('<NOTES>', $host['notes'], $msg);
|
|
$msg = thold_str_replace("\n", '<br>', $msg);
|
|
|
|
switch ($host['thold_send_email']) {
|
|
case '0': // Disabled
|
|
$alert_email = '';
|
|
|
|
break;
|
|
case '1': // Global List
|
|
break;
|
|
case '2': // Devices List Only
|
|
$alert_email = get_thold_notification_emails($host['thold_host_email']);
|
|
$notify_list_id = $host['thold_host_email'];
|
|
|
|
break;
|
|
case '3': // Global and Devices List
|
|
$alert_email = $alert_email . ',' . get_thold_notification_emails($host['thold_host_email']);
|
|
$notify_list_id = $host['thold_host_email'];
|
|
|
|
break;
|
|
}
|
|
|
|
api_plugin_hook_function(
|
|
'thold_device_down',
|
|
[
|
|
'device' => $host,
|
|
'subject' => $subject,
|
|
'message' => $msg,
|
|
'email' => $alert_email
|
|
]
|
|
);
|
|
|
|
cacti_log('WARNING: Device[' . $host['id'] . '] Hostname[' . $host['hostname'] . '] is down!', true, 'THOLD');
|
|
|
|
if ($alert_email == '' && $host['thold_send_email'] > 0) {
|
|
cacti_log('WARNING: Device[' . $host['id'] . '] Hostname[' . $host['hostname'] . '] can not send a Device down email for \'' . $host['description'] . '\' since the \'Alert Email\' setting is not set for Device!', true, 'THOLD');
|
|
} elseif ($host['thold_send_email'] == '0') {
|
|
cacti_log('NOTE: Device[' . $host['id'] . '] Hostname[' . $host['hostname'] . '] did not send a Device down email for \'' . $host['description'] . '\', disabled per Device setting!', true, 'THOLD');
|
|
} elseif ($alert_email != '') {
|
|
thold_mail($alert_email, '', '', $subject, $msg, '', '', $notify_list_id, $host, '', 7, 'thold_dhost_mail');
|
|
}
|
|
|
|
$command = read_config_option('thold_device_command');
|
|
|
|
if ($command != '') {
|
|
thold_putenv('THOLD_SUBJECT=' . $subject);
|
|
thold_putenv('THOLD_HOSTNAME=' . $host['hostname']);
|
|
thold_putenv('THOLD_HOST_ID=' . $host['id']);
|
|
thold_putenv('THOLD_DESCRIPTION=' . $host['description']);
|
|
thold_putenv('THOLD_SITE=' . $site);
|
|
thold_putenv('THOLD_LOCATION=' . $host['location']);
|
|
thold_putenv('THOLD_TIME=' . time());
|
|
thold_putenv('THOLD_DATE=' . date(CACTI_DATE_TIME_FORMAT));
|
|
thold_putenv('THOLD_DATE_RFC822=' . date(DATE_RFC822));
|
|
|
|
thold_putenv('THOLD_UPTIME=');
|
|
thold_putenv('THOLD_DOWNTIME=' . $last_time_duration);
|
|
thold_putenv('THOLD_MESSAGE=' . $host['status_last_error']);
|
|
thold_putenv('THOLD_DOWNUP=' . 'DOWN');
|
|
|
|
thold_putenv('THOLD_SNMP_HOSTNAME=' . $host['snmp_sysName']);
|
|
thold_putenv('THOLD_SNMP_LOCATION=' . $host['snmp_sysLocation']);
|
|
thold_putenv('THOLD_SNMP_CONTACT=' . $host['snmp_sysContact']);
|
|
thold_putenv('THOLD_SNMP_SYSTEM=');
|
|
thold_putenv('THOLD_LAST_FAIL=' . $host['status_fail_date']);
|
|
thold_putenv('THOLD_AVAILABILITY=' . $host['availability']);
|
|
thold_putenv('THOLD_TOT_POLL=' . $host['total_polls']);
|
|
thold_putenv('THOLD_FAIL_POLL=' . $host['failed_polls']);
|
|
thold_putenv('THOLD_CUR_TIME=' . $host['cur_time']);
|
|
thold_putenv('THOLD_AVG_TIME=' . $host['avg_time']);
|
|
$environment = thold_putenv('THOLD_NOTES=' . $host['notes']);
|
|
|
|
if (file_exists($command) && is_executable($command)) {
|
|
$output = [];
|
|
$return = 0;
|
|
|
|
if ($queue == '') {
|
|
exec($command, $output, $return);
|
|
|
|
cacti_log('Device Down Command for Device[' . $host['id'] . '] Command[' . $command . '] ExitStatus[' . $return . '] Output[' . implode(' ', $output) . ']', false, 'THOLD');
|
|
} else {
|
|
$data = [
|
|
'command' => $command,
|
|
'data' => $host,
|
|
'environment' => $environment
|
|
];
|
|
|
|
thold_notification_add('thold_dhost_cmd', $data, 'id', $notify_list_id, $host);
|
|
}
|
|
} else {
|
|
cacti_log('WARNING: Device Down Command for Device[' . $host['id'] . '] Command[' . $command . '] Is either Not found or Not executable!', false, 'THOLD');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Now lets record all failed hosts
|
|
if (read_config_option('remote_storage_method') == 1) {
|
|
db_execute_prepared('DELETE
|
|
FROM plugin_thold_host_failed
|
|
WHERE poller_id = ?',
|
|
[$config['poller_id']]);
|
|
|
|
$hosts = db_fetch_assoc_prepared('SELECT id, status, hostname
|
|
FROM host
|
|
WHERE disabled = ""
|
|
AND poller_id = ?
|
|
AND ((status != ? AND status != ?)
|
|
OR (status = ? AND status_event_count >= IF(thold_failure_count > 0, thold_failure_count, ?))) ',
|
|
[$config['poller_id'], HOST_UP, HOST_DOWN, HOST_DOWN, $ping_failure_count]);
|
|
|
|
set_config_option('time_last_change_thold_device', time());
|
|
} else {
|
|
db_execute('TRUNCATE plugin_thold_host_failed');
|
|
|
|
$hosts = db_fetch_assoc_prepared('SELECT id, status, hostname
|
|
FROM host
|
|
WHERE disabled = ""
|
|
AND ((status != ? AND status != ?)
|
|
OR (status = ? AND status_event_count >= IF(thold_failure_count > 0, thold_failure_count, ?))) ',
|
|
[HOST_UP, HOST_DOWN, HOST_DOWN, $ping_failure_count]);
|
|
|
|
set_config_option('time_last_change_thold_device', time());
|
|
}
|
|
|
|
if (cacti_sizeof($hosts)) {
|
|
$failed_ids = '';
|
|
|
|
foreach ($hosts as $host) {
|
|
// hosts in recovery status record only if they was in failed status
|
|
if (($host['status'] != HOST_RECOVERING) || ($host['status'] == HOST_RECOVERING && (is_array($failed) && array_search($host['id'], array_column($failed, 'host_id'), true) !== false))) {
|
|
$failed_ids .= ($failed_ids != '' ? '), (' : '(') . $host['id'];
|
|
}
|
|
}
|
|
|
|
$failed_ids .= $failed_ids != '' ? ')' : '';
|
|
|
|
if ($failed_ids != '') {
|
|
db_execute("INSERT INTO plugin_thold_host_failed
|
|
(host_id)
|
|
VALUES $failed_ids");
|
|
|
|
set_config_option('time_last_change_thold_device', time());
|
|
}
|
|
}
|
|
|
|
return $total_hosts;
|
|
}
|