mirror of
https://github.com/Cacti/cacti.git
synced 2026-10-29 08:06:58 +09:00
* fix: match spine's unconditional engine-time preference for SNMP uptime recache (develop) PR #7982 changed cacti_snmp_select_uptime() to prefer whichever of sysUpTime and snmpEngineTime is numerically larger. Spine's own reindex-assert re-check (poller.c) has no such magnitude comparison - it always prefers a numeric engine time, only falling back to sysUpTime when the engine OID isn't present. For any device where snmpEngineTime is legitimately smaller than sysUpTime (e.g. the SNMP agent/engine restarted more recently than the OS, a common, unremarkable scenario), lib/poller.php's update_reindex_cache() now picks sysUpTime as the recache baseline while spine always re-derives its live comparison value from the smaller engine time. Every poll then reports "RECACHE ASSERT FAILED" and queues a reindex; Cacti recomputes the baseline the same way, so it never converges - an infinite RECACHE ASSERT loop that looks like a spine bug even though spine is unchanged. Fix: add an opt-in $prefer_engine_time parameter to cacti_snmp_select_uptime() that keeps the existing wall-clock rejection (issue#7342) but skips the "prefer whichever is larger" comparison, matching spine's rule exactly. Use it for the two call sites that must stay consistent with spine's own live re-check: lib/poller.php's recache baseline, and both uptime reads in cmd.php (update_system_mibs()'s host.snmp_sysUpTimeInstance update, and ping_and_reindex_check()'s own PHP-poller equivalent of spine's reindex re-check). The display-only call sites (lib/api_device.php, lib/api_automation.php) keep the existing wrap-aware "prefer larger" logic, since they aren't compared against a persisted, spine-shared baseline. Ported from the 1.2.x fix (#8057). Added tests covering the new parameter and asserting both call sites opt into it. * test(snmp): cover prefer_engine_time in the coverage-gated suite phpunit-snmp.xml's "SNMP coverage" testsuite only runs SnmpCoverageTest.php, not SnmpUptimeSelectionTest.php where the new $prefer_engine_time assertions were added. The engine-time-preference branch in cacti_snmp_select_uptime() was never executed under the 100% line coverage gate, so the "lib/snmp.php 100% coverage" check failed at 99.8%. Mirror the same prefer_engine_time assertions into SnmpCoverageTest.php so the coverage-gated suite exercises the new branch. * fix: match spine's lack of wall-clock awareness for prefer_engine_time paths The wall-clock rejection guard ran before the prefer_engine_time branch, so an OpenBSD-style agent (engine time == Unix clock) still fell back to sysUpTime on the spine-facing paths even with prefer_engine_time=true. Spine's own re-check has no wall-clock awareness at all - it unconditionally prefers any numeric engine time - so that class of device kept the RECACHE ASSERT loop. Move the prefer_engine_time short-circuit before the wall-clock check so those paths replicate spine exactly; the wall-clock rejection still protects the display-only call sites. * test(snmp): fix stale wall-clock assumption in prefer_engine_time coverage test
77 lines
3.4 KiB
PHP
77 lines
3.4 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. |
|
|
| |
|
|
| Cacti: The Complete RRDtool-based Graphing Solution |
|
|
+-------------------------------------------------------------------------+
|
|
*/
|
|
|
|
declare(strict_types = 1);
|
|
|
|
$root = dirname(__DIR__, 4);
|
|
|
|
require_once $root . '/lib/snmp.php';
|
|
|
|
test('issue 7342 rejects an snmpEngineTime value that is the Unix clock', function (): void {
|
|
$now = 1784363931;
|
|
|
|
expect(cacti_snmp_select_uptime(3015, $now, $now))->toBe(3015);
|
|
});
|
|
|
|
test('normal engine time still covers a wrapped sysUpTime value', function (): void {
|
|
$now = 1784363931;
|
|
|
|
expect(cacti_snmp_select_uptime(250000, 50000000, $now))->toBe(5000000000)
|
|
->and(cacti_snmp_select_uptime(4000000, 600, $now))->toBe(4000000)
|
|
->and(cacti_snmp_select_uptime(false, 600, $now))->toBe(60000)
|
|
->and(cacti_snmp_select_uptime('U', 'U', $now))->toBeFalse();
|
|
});
|
|
|
|
test('prefer_engine_time matches spine\'s own unconditional engine-OID preference', function (): void {
|
|
$now = 1784363931;
|
|
|
|
// spine (poller.c) always prefers a numeric engine time over sysUpTime with no
|
|
// magnitude comparison and no wall-clock awareness of its own; a smaller-but-
|
|
// legitimate engine time (e.g. the SNMP agent restarted more recently than the OS)
|
|
// must not fall back to sysUpTime here, or the recache baseline permanently
|
|
// disagrees with spine's live re-check
|
|
expect(cacti_snmp_select_uptime(999999999, 600, $now, true))->toBe(60000)
|
|
->and(cacti_snmp_select_uptime(4000000, 600, $now, true))->toBe(60000)
|
|
->and(cacti_snmp_select_uptime(false, 600, $now, true))->toBe(60000)
|
|
// spine has no wall-clock rejection either, so an OpenBSD-style engine time
|
|
// that looks like the Unix clock must still be used here, not rejected -
|
|
// otherwise this exact class of device keeps the RECACHE ASSERT loop
|
|
->and(cacti_snmp_select_uptime(3015, $now, $now, true))->toBe($now * 100)
|
|
->and(cacti_snmp_select_uptime('U', 'U', $now, true))->toBeFalse();
|
|
});
|
|
|
|
test('every system uptime consumer delegates to the shared selector', function () use ($root): void {
|
|
$callCounts = [
|
|
'cmd.php' => 2,
|
|
'lib/poller.php' => 1,
|
|
'lib/api_device.php' => 1,
|
|
'lib/api_automation.php' => 1,
|
|
];
|
|
|
|
foreach ($callCounts as $path => $count) {
|
|
$source = file_get_contents($root . '/' . $path);
|
|
|
|
expect($source)->not->toBeFalse("$path must be readable")
|
|
->and(substr_count($source, 'cacti_snmp_select_uptime('))->toBeGreaterThanOrEqual($count);
|
|
}
|
|
});
|
|
|
|
test('the recache baseline and cmd.php reindex re-check opt into spine-compatible engine preference', function () use ($root): void {
|
|
$pollerSource = file_get_contents($root . '/lib/poller.php');
|
|
$cmdSource = file_get_contents($root . '/cmd.php');
|
|
|
|
expect($pollerSource)->toContain('cacti_snmp_select_uptime($system_uptime, $engine_time, null, true)')
|
|
->and(substr_count($cmdSource, 'cacti_snmp_select_uptime($system_uptime, $engine_time, null, true)'))->toBe(2);
|
|
});
|