Files
Cactiplugin_thold/includes/polling.php
T

886 lines
35 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/ |
+-------------------------------------------------------------------------+
*/
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');
}
}
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());
}
}
function thold_poller_output(&$rrd_update_array) {
global $config, $debug;
include_once($config['base_path'] . '/plugins/thold/thold_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') {
$chunks = ceil(sizeof($rrd_update_array) / 50);
if ($chunks < 1) {
$chunks = 1;
}
$rrd_update_array_chunks = array_chunk($rrd_update_array, $chunks, 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
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 = [];
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') {
$currentval = strtolower($currentval);
if ($currentval == 'u' || $currentval == 'nan' || $currentval == '') {
$currentval = 0;
thold_debug('Threshold: ' . $thold_data['thold_name'] . ' changing unknown value to zero', 'thold');
if (read_config_option('thold_log_unknown_to_zero') == 'on') {
cacti_log('NOTE: Threshold \'' . $thold_data['thold_name'] . '\' changing unknown value to zero', true, 'THOLD');
}
} else {
$currentval = '';
}
} else {
$currentval = '';
}
}
// This stores the raw value into the data source and is important for
// Counters, where calculating the difference is important.
// The unset case is problematic and may lead to false triggering
// events. So, in those cases, we will store the 'oldvalue'.
if (isset($item[$thold_data['name']])) {
$rawvalue = $item[$thold_data['name']];
} else {
$rawvalue = $thold_data['oldvalue'];
}
$sql[] = '(' . $thold_data['id'] . ', 1, ' . db_qstr($currentval) . ', FROM_UNIXTIME(' . $currenttime . '), ' . db_qstr($rawvalue) . ')';
}
if (cacti_sizeof($sql)) {
$chunks = array_chunk($sql, 400);
foreach ($chunks as $c) {
db_execute('INSERT INTO thold_data
(id, tcheck, lastread, lasttime, oldvalue)
VALUES ' . implode(', ', $c) . '
ON DUPLICATE KEY UPDATE
tcheck = VALUES(tcheck),
lastread = VALUES(lastread),
lasttime = VALUES(lasttime),
oldvalue = VALUES(oldvalue)');
}
// accommodate deleted tholds
db_execute('DELETE FROM thold_data WHERE local_data_id = 0');
if (db_affected_rows() > 0) {
set_config_option('time_last_change_thold', time());
}
}
}
return $rrd_update_array;
}
if (!function_exists('array_column')) {
function array_column($array, $column_name) {
return array_map(function ($element) use ($column_name) {
return $element[$column_name];
}, $array);
}
}
function thold_check_all_thresholds() {
global $config;
include($config['base_path'] . '/plugins/thold/includes/arrays.php');
include_once($config['base_path'] . '/plugins/thold/thold_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);
foreach ($tholds as $thold) {
thold_check_threshold($thold);
}
if (read_config_option('remote_storage_method') == 1) {
if ($config['poller_id'] == 1) {
db_execute('UPDATE thold_data AS td
LEFT JOIN host AS h
ON td.host_id = h.id
SET tcheck = 0
WHERE h.poller_id = 1
OR h.poller_id IS NULL');
} else {
db_execute_prepared('UPDATE thold_data AS td
INNER JOIN host AS h
ON td.host_id = h.id
SET td.tcheck = 0
WHERE h.poller_id = ?',
[$config['poller_id']]);
}
} else {
db_execute('UPDATE thold_data AS td SET td.tcheck = 0');
}
return $total_tholds;
}
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/thold_functions.php');
include_once($config['library_path'] . '/snmp.php');
if (api_plugin_is_enabled('maint')) {
include_once($config['base_path'] . '/plugins/maint/functions.php');
}
$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') && 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') && 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;
}