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 (#859)
* 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>
This commit is contained in:
1 parent
dd2abc92cd
commit
2c7593c990
4 files changed
+132
-3
No files matched your search
@@ -3423,7 +3423,7 @@ function thold_check_threshold(&$thold_data) {
|
||||
}
|
||||
}
|
||||
|
||||
if (api_plugin_is_enabled('maint') && plugin_maint_check_cacti_host($thold_data['host_id'])) {
|
||||
if (api_plugin_is_enabled('maint') && function_exists('plugin_maint_check_cacti_host') && plugin_maint_check_cacti_host($thold_data['host_id'])) {
|
||||
$maint_dev = true;
|
||||
} else {
|
||||
$maint_dev = false;
|
||||
|
||||
@@ -637,7 +637,7 @@ function thold_update_host_status() {
|
||||
$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'])) {
|
||||
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']) {
|
||||
@@ -764,7 +764,7 @@ function thold_update_host_status() {
|
||||
|
||||
$alert_email = read_config_option('alert_email');
|
||||
|
||||
if (api_plugin_is_enabled('maint') && plugin_maint_check_cacti_host($host['id'])) {
|
||||
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) {
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
<?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. |
|
||||
+-------------------------------------------------------------------------+
|
||||
| Cacti: The Complete RRDtool-based Graphing Solution |
|
||||
+-------------------------------------------------------------------------+
|
||||
| http://www.cacti.net/ |
|
||||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/**
|
||||
* thold_update_host_status() consults the maint plugin for both the
|
||||
* recovering-device and down-device notification loops. The call is now
|
||||
* guarded by function_exists('plugin_maint_check_cacti_host') so a maint
|
||||
* plugin that is enabled but whose functions file could not be included no
|
||||
* longer fatals with an undefined-function error. These tests drive both
|
||||
* maintenance-gated branches so that guard stays in place.
|
||||
*/
|
||||
final class MaintCheckGuardTest extends TestCase {
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public static function setUpBeforeClass(): void {
|
||||
self::loadPluginSource('includes/functions.php');
|
||||
self::loadPluginSource('includes/polling.php');
|
||||
self::loadPluginSourceAlways('includes/arrays.php');
|
||||
self::loadPluginConstants();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
private function maintIncludesRoot() {
|
||||
return dirname(__DIR__) . '/Fixtures/cacti-root-maint-includes';
|
||||
}
|
||||
|
||||
/**
|
||||
* Run thold_update_host_status() against the newer maint layout. A device
|
||||
* inside a maintenance window is logged and the loop moves on without the
|
||||
* downstream notification work, so the call returns on its own. Expected
|
||||
* engine warnings are suppressed, but no Throwable is swallowed, so an
|
||||
* unexpected error (e.g. a removed guard fataling on an undefined maint
|
||||
* function) fails the test.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function runHostStatus() {
|
||||
CactiStubs::willAlwaysReturn('api_plugin_is_enabled', true);
|
||||
CactiStubs::willAlwaysReturn('plugin_maint_check_cacti_host', true);
|
||||
CactiStubs::$configOptions['alert_deadnotify'] = 'on';
|
||||
$GLOBALS['config']['base_path'] = $this->maintIncludesRoot();
|
||||
|
||||
set_error_handler(static fn (): bool => true);
|
||||
ob_start();
|
||||
|
||||
try {
|
||||
thold_update_host_status();
|
||||
} finally {
|
||||
ob_end_clean();
|
||||
restore_error_handler();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A recovered device inside a maintenance window is logged, not alerted.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testRecoveringDeviceInMaintenanceIsLoggedNotAlerted(): void {
|
||||
CactiStubs::willReturnFor('db_fetch_assoc', 'plugin_thold_host_failed', [['host_id' => 42]]);
|
||||
CactiStubs::willReturnFor('db_fetch_row_prepared', 'FROM host WHERE id', [
|
||||
'id' => 42,
|
||||
'hostname' => 'dev42',
|
||||
'description' => 'Device 42',
|
||||
'status' => HOST_UP,
|
||||
'snmp_community' => '',
|
||||
'snmp_username' => '',
|
||||
'snmp_version' => 0,
|
||||
'site_id' => 0,
|
||||
'location' => '',
|
||||
'notes' => '',
|
||||
'status_fail_date' => '0000-00-00 00:00:00',
|
||||
'availability' => 100,
|
||||
'total_polls' => 1,
|
||||
'failed_polls' => 0,
|
||||
'cur_time' => 0,
|
||||
'avg_time' => 0,
|
||||
'thold_send_email' => '0',
|
||||
]);
|
||||
|
||||
$this->runHostStatus();
|
||||
|
||||
$this->assertContains(
|
||||
'WARNING: Device[42] Hostname[dev42] is recovering! Only logging, maint device',
|
||||
CactiStubs::$log
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* A down device inside a maintenance window is logged, not alerted.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testDownDeviceInMaintenanceIsLoggedNotAlerted(): void {
|
||||
CactiStubs::willReturnFor('db_fetch_assoc_prepared', 'availability_method', [[
|
||||
'id' => 77,
|
||||
'hostname' => 'dev77',
|
||||
]]);
|
||||
|
||||
$this->runHostStatus();
|
||||
|
||||
$this->assertContains(
|
||||
'WARNING: Device[77] Hostname[dev77] is DOWN. Only logging, maint device',
|
||||
CactiStubs::$log
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -669,6 +669,12 @@ if (!function_exists('number_format_i18n')) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('html_split_string')) {
|
||||
function html_split_string($string, $length = 76, $forgiving = 10) {
|
||||
return $string;
|
||||
}
|
||||
}
|
||||
|
||||
if (!defined('FILTER_VALIDATE_IS_REGEX')) {
|
||||
define('FILTER_VALIDATE_IS_REGEX', 99999);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user