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>
789 lines
23 KiB
PHP
789 lines
23 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 |
|
|
+-------------------------------------------------------------------------+
|
|
| http://www.cacti.net/ |
|
|
+-------------------------------------------------------------------------+
|
|
*/
|
|
|
|
/*
|
|
* Test bootstrap.
|
|
*
|
|
* thold's sources expect to be included by Cacti, which has already defined
|
|
* the db_*, request-variable, and logging helpers as plain global functions.
|
|
* Nothing here talks to a database or a network: each Cacti function is
|
|
* declared as a shim over CactiStubs, which records the call and hands back
|
|
* whatever the test programmed.
|
|
*
|
|
* Guarding every declaration with function_exists() keeps this file usable if
|
|
* a future integration suite loads real Cacti first.
|
|
*/
|
|
|
|
$cacti_root = dirname(__DIR__, 3);
|
|
$autoload = $cacti_root . '/include/vendor/autoload.php';
|
|
$version = $cacti_root . '/include/cacti_version';
|
|
$expected = __DIR__ . '/.cacti-version';
|
|
|
|
if (!is_readable($autoload)) {
|
|
throw new RuntimeException("Cacti Composer autoloader is not readable: $autoload");
|
|
}
|
|
|
|
if (!is_readable($version)) {
|
|
throw new RuntimeException("Cacti version file is not readable: $version");
|
|
}
|
|
|
|
if (!is_readable($expected)) {
|
|
throw new RuntimeException("Expected Cacti version file is not readable: $expected");
|
|
}
|
|
|
|
$cacti_version = trim((string) file_get_contents($version));
|
|
$expected_version = trim((string) file_get_contents($expected));
|
|
|
|
if ($cacti_version === '') {
|
|
throw new RuntimeException("Cacti version file is empty: $version");
|
|
}
|
|
|
|
if ($expected_version === '') {
|
|
throw new RuntimeException("Expected Cacti version file is empty: $expected");
|
|
}
|
|
|
|
// The CI workflow tracks a moving branch (1.2.x or develop) rather than a pinned release, so any actual version is accepted.
|
|
if (!in_array($expected_version, ['1.2.x', 'develop'], true) && $cacti_version !== $expected_version) {
|
|
throw new RuntimeException("Expected Cacti $expected_version, found $cacti_version in $version");
|
|
}
|
|
|
|
require_once $autoload;
|
|
require_once __DIR__ . '/Helpers/CactiStubs.php';
|
|
require_once __DIR__ . '/TestCase.php';
|
|
require_once __DIR__ . '/Helpers/ThresholdOutcome.php';
|
|
require_once __DIR__ . '/Helpers/ThresholdScenario.php';
|
|
|
|
if (!defined('POLLER_VERBOSITY_MEDIUM')) {
|
|
define('POLLER_VERBOSITY_MEDIUM', 3);
|
|
}
|
|
|
|
/*
|
|
* base_path has to point at the Cacti root two levels above this plugin:
|
|
* includes/functions.php builds include paths from it at runtime.
|
|
*/
|
|
$GLOBALS['config'] = [
|
|
'base_path' => $cacti_root,
|
|
'url_path' => '/cacti/',
|
|
'cacti_version' => $cacti_version,
|
|
'cacti_server_os' => 'unix',
|
|
];
|
|
$GLOBALS['__test_original_base_path'] = $cacti_root;
|
|
|
|
// thold_expand_string() include_once()s library_path/variables.php at call time.
|
|
$GLOBALS['config']['library_path'] = __DIR__ . '/Fixtures/cacti-lib';
|
|
|
|
// thold reads and writes this on every RPN evaluation.
|
|
$GLOBALS['rpn_error'] = false;
|
|
|
|
// Cacti's list of enabled plugins; thold_check_threshold() declares it global.
|
|
$GLOBALS['plugins'] = [];
|
|
|
|
// Cacti's debug flag, also declared global by thold_check_threshold().
|
|
$GLOBALS['debug'] = false;
|
|
|
|
if (!function_exists('db_execute')) {
|
|
function db_execute($sql, $log = true, $db_conn = false) {
|
|
CactiStubs::record('db_execute', $sql);
|
|
|
|
return CactiStubs::nextReturn('db_execute', true, $sql);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('db_execute_prepared')) {
|
|
function db_execute_prepared($sql, $params = [], $log = true, $db_conn = false) {
|
|
CactiStubs::record('db_execute_prepared', $sql, $params);
|
|
|
|
return CactiStubs::nextReturn('db_execute_prepared', true, $sql);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('register_process_start')) {
|
|
function register_process_start($tasktype, $taskname, $taskid = 0, $timeout = 300) {
|
|
CactiStubs::record('register_process_start', '', [$tasktype, $taskname, $taskid, $timeout]);
|
|
|
|
return CactiStubs::nextReturn('register_process_start', true);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('unregister_process')) {
|
|
function unregister_process($tasktype, $taskname, $taskid = 0, $pid = -1) {
|
|
CactiStubs::record('unregister_process', '', [$tasktype, $taskname, $taskid, $pid]);
|
|
|
|
return CactiStubs::nextReturn('unregister_process', true);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('heartbeat_process')) {
|
|
function heartbeat_process($tasktype, $taskname, $taskid = 0) {
|
|
CactiStubs::record('heartbeat_process', '', [$tasktype, $taskname, $taskid]);
|
|
|
|
return CactiStubs::nextReturn('heartbeat_process', true);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('db_fetch_assoc')) {
|
|
function db_fetch_assoc($sql, $log = true, $db_conn = false) {
|
|
CactiStubs::record('db_fetch_assoc', $sql);
|
|
|
|
return CactiStubs::nextReturn('db_fetch_assoc', [], $sql);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('db_fetch_assoc_prepared')) {
|
|
function db_fetch_assoc_prepared($sql, $params = [], $log = true, $db_conn = false) {
|
|
CactiStubs::record('db_fetch_assoc_prepared', $sql, $params);
|
|
|
|
return CactiStubs::nextReturn('db_fetch_assoc_prepared', [], $sql);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('db_fetch_row')) {
|
|
function db_fetch_row($sql, $log = true, $db_conn = false) {
|
|
CactiStubs::record('db_fetch_row', $sql);
|
|
|
|
return CactiStubs::nextReturn('db_fetch_row', [], $sql);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('db_fetch_row_prepared')) {
|
|
function db_fetch_row_prepared($sql, $params = [], $log = true, $db_conn = false) {
|
|
CactiStubs::record('db_fetch_row_prepared', $sql, $params);
|
|
|
|
return CactiStubs::nextReturn('db_fetch_row_prepared', [], $sql);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Cacti's cell fetchers return false, not '', when the query matches no row.
|
|
* The difference matters on PHP 8: false coerces to 0 in arithmetic while ''
|
|
* raises a TypeError, so a stub returning '' invents failures that production
|
|
* does not have.
|
|
*/
|
|
if (!function_exists('db_fetch_cell')) {
|
|
function db_fetch_cell($sql, $col_name = '', $log = true, $db_conn = false) {
|
|
CactiStubs::record('db_fetch_cell', $sql);
|
|
|
|
return CactiStubs::nextReturn('db_fetch_cell', false, $sql);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('db_fetch_cell_prepared')) {
|
|
function db_fetch_cell_prepared($sql, $params = [], $col_name = '', $log = true, $db_conn = false) {
|
|
CactiStubs::record('db_fetch_cell_prepared', $sql, $params);
|
|
|
|
return CactiStubs::nextReturn('db_fetch_cell_prepared', false, $sql);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('db_qstr')) {
|
|
function db_qstr($string, $db_conn = false) {
|
|
return "'" . str_replace("'", "''", (string) $string) . "'";
|
|
}
|
|
}
|
|
|
|
if (!function_exists('db_begin_transaction')) {
|
|
function db_begin_transaction() {
|
|
CactiStubs::record('db_begin_transaction');
|
|
|
|
return CactiStubs::nextReturn('db_begin_transaction', true);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('db_commit_transaction')) {
|
|
function db_commit_transaction() {
|
|
CactiStubs::record('db_commit_transaction');
|
|
|
|
return CactiStubs::nextReturn('db_commit_transaction', true);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('db_rollback_transaction')) {
|
|
function db_rollback_transaction() {
|
|
CactiStubs::record('db_rollback_transaction');
|
|
|
|
return CactiStubs::nextReturn('db_rollback_transaction', true);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('html_escape')) {
|
|
function html_escape($string) {
|
|
return htmlspecialchars((string) $string, ENT_QUOTES, 'UTF-8');
|
|
}
|
|
}
|
|
|
|
// Output-only Cacti UI helpers the page_head/device hook callbacks emit
|
|
// through; the tests only care that the surrounding PHP (including the CSP
|
|
// nonce/asset lines) executes, so these are recorded no-ops.
|
|
if (!function_exists('html_header')) {
|
|
function html_header(...$args) {
|
|
CactiStubs::record('html_header');
|
|
}
|
|
}
|
|
|
|
if (!function_exists('html_start_box')) {
|
|
function html_start_box(...$args) {
|
|
CactiStubs::record('html_start_box');
|
|
}
|
|
}
|
|
|
|
if (!function_exists('html_end_box')) {
|
|
function html_end_box(...$args) {
|
|
CactiStubs::record('html_end_box');
|
|
}
|
|
}
|
|
|
|
if (!function_exists('form_start')) {
|
|
function form_start(...$args) {
|
|
CactiStubs::record('form_start');
|
|
}
|
|
}
|
|
|
|
if (!function_exists('form_end')) {
|
|
function form_end(...$args) {
|
|
CactiStubs::record('form_end');
|
|
}
|
|
}
|
|
|
|
if (!function_exists('form_alternate_row')) {
|
|
function form_alternate_row(...$args) {
|
|
CactiStubs::record('form_alternate_row');
|
|
}
|
|
}
|
|
|
|
if (!function_exists('form_end_row')) {
|
|
function form_end_row(...$args) {
|
|
CactiStubs::record('form_end_row');
|
|
}
|
|
}
|
|
|
|
if (!function_exists('form_dropdown')) {
|
|
function form_dropdown(...$args) {
|
|
CactiStubs::record('form_dropdown');
|
|
}
|
|
}
|
|
|
|
if (!function_exists('get_md5_include_js')) {
|
|
function get_md5_include_js($path, $async = false) {
|
|
return "<script type='text/javascript' src='" . $path . "'></script>";
|
|
}
|
|
}
|
|
|
|
if (!function_exists('get_md5_include_css')) {
|
|
function get_md5_include_css($path) {
|
|
return "<link href='" . $path . "' type='text/css' rel='stylesheet'>";
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Mirrors Cacti 1.2 lib/functions.php. KEEP IN SYNC: if core tightens its
|
|
* checks, tests here would otherwise keep passing while production diverges.
|
|
*/
|
|
if (!function_exists('sanitize_unserialize_selected_items')) {
|
|
function sanitize_unserialize_selected_items($items) {
|
|
if (empty($items)) {
|
|
return false;
|
|
}
|
|
|
|
$data = unserialize($items, ['allowed_classes' => false]); // nosemgrep: php.lang.security.unserialize-use.unserialize-use -- test stub mirroring Cacti core; allowed_classes:false blocks object injection
|
|
|
|
if (!is_array($data)) {
|
|
return false;
|
|
}
|
|
|
|
foreach ($data as $value) {
|
|
if (!is_numeric($value)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
}
|
|
|
|
if (!function_exists('read_config_option')) {
|
|
function read_config_option($name, $force = false) {
|
|
return isset(CactiStubs::$configOptions[$name]) ? CactiStubs::$configOptions[$name] : '';
|
|
}
|
|
}
|
|
|
|
if (!function_exists('set_config_option')) {
|
|
function set_config_option($name, $value) {
|
|
CactiStubs::$configOptions[$name] = $value;
|
|
}
|
|
}
|
|
|
|
if (!function_exists('__')) {
|
|
function __($text) {
|
|
$args = array_slice(func_get_args(), 1);
|
|
|
|
// Cacti's __() accepts sprintf arguments after the format string.
|
|
return $args === [] ? $text : vsprintf($text, $args);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('__esc')) {
|
|
function __esc($text) {
|
|
return htmlspecialchars(call_user_func_array('__', func_get_args()), ENT_QUOTES, 'UTF-8');
|
|
}
|
|
}
|
|
|
|
if (!function_exists('cacti_log')) {
|
|
function cacti_log($message, $output = false, $environ = 'CMDPHP', $level = 0) {
|
|
CactiStubs::$log[] = $message;
|
|
$GLOBALS['__test_cacti_log'][] = (string) $message;
|
|
CactiStubs::record('cacti_log', '', [$message, $output, $environ, $level]);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('cacti_sizeof')) {
|
|
function cacti_sizeof($array) {
|
|
return (is_array($array) || $array instanceof Countable) ? count($array) : 0;
|
|
}
|
|
}
|
|
|
|
if (!function_exists('cacti_count')) {
|
|
function cacti_count($array) {
|
|
return cacti_sizeof($array);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('get_request_var')) {
|
|
function get_request_var($name, $default = '') {
|
|
return isset(CactiStubs::$requestVars[$name]) ? CactiStubs::$requestVars[$name] : $default;
|
|
}
|
|
}
|
|
|
|
if (!function_exists('get_nfilter_request_var')) {
|
|
function get_nfilter_request_var($name, $default = '') {
|
|
return get_request_var($name, $default);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('get_filter_request_var')) {
|
|
function get_filter_request_var($name, $filter = FILTER_VALIDATE_INT, $options = []) {
|
|
return get_request_var($name);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('isset_request_var')) {
|
|
function isset_request_var($name) {
|
|
return isset(CactiStubs::$requestVars[$name]);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('isempty_request_var')) {
|
|
function isempty_request_var($name) {
|
|
return !isset(CactiStubs::$requestVars[$name]) || CactiStubs::$requestVars[$name] === '';
|
|
}
|
|
}
|
|
|
|
if (!function_exists('set_request_var')) {
|
|
function set_request_var($name, $value) {
|
|
CactiStubs::$requestVars[$name] = $value;
|
|
}
|
|
}
|
|
|
|
if (!function_exists('cacti_escapeshellarg')) {
|
|
function cacti_escapeshellarg($string, $quote = true) {
|
|
return escapeshellarg((string) $string);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('api_plugin_hook_function')) {
|
|
function api_plugin_hook_function($name, $data = '') {
|
|
return $data;
|
|
}
|
|
}
|
|
|
|
if (!function_exists('get_simple_graph_perms')) {
|
|
function get_simple_graph_perms($user_id) {
|
|
return CactiStubs::nextReturn('get_simple_graph_perms', true);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('get_policies')) {
|
|
function get_policies($user_id) {
|
|
return CactiStubs::nextReturn('get_policies', []);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('get_policy_where')) {
|
|
function get_policy_where($graph_auth_method, $policies, $sql_where) {
|
|
CactiStubs::record('get_policy_where', $sql_where);
|
|
|
|
return CactiStubs::nextReturn('get_policy_where', $sql_where);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('expand_title')) {
|
|
function expand_title($host_id, $snmp_query_id, $snmp_index, $title) {
|
|
CactiStubs::record('expand_title', $title);
|
|
|
|
return CactiStubs::nextReturn('expand_title', $title);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('substitute_host_data')) {
|
|
function substitute_host_data($string, $l_escape_string, $r_escape_string, $host_id) {
|
|
CactiStubs::record('substitute_host_data', $string);
|
|
|
|
return CactiStubs::nextReturn('substitute_host_data', $string);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('null_out_substitutions')) {
|
|
function null_out_substitutions($string) {
|
|
return CactiStubs::nextReturn('null_out_substitutions', $string);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('get_graph_title')) {
|
|
function get_graph_title($local_graph_id) {
|
|
return CactiStubs::nextReturn('get_graph_title', 'Traffic - eth0');
|
|
}
|
|
}
|
|
|
|
if (!function_exists('rrdtool_function_fetch')) {
|
|
function rrdtool_function_fetch($local_data_id, $start_time, $end_time, $resolution = 0, $show_unknown = false, $rrdtool_file = null) {
|
|
CactiStubs::record('rrdtool_function_fetch', (string) $local_data_id);
|
|
|
|
return CactiStubs::nextReturn('rrdtool_function_fetch', []);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('get_data_source_path')) {
|
|
function get_data_source_path($local_data_id, $expand_paths = true) {
|
|
return '/var/lib/cacti/rra/test_' . (int) $local_data_id . '.rrd';
|
|
}
|
|
}
|
|
|
|
if (!function_exists('sql_save')) {
|
|
function sql_save($array_items, $table_name, $key_cols = 'id', $autoinc = true, $db_conn = false) {
|
|
CactiStubs::record('sql_save', $table_name, $array_items);
|
|
|
|
return CactiStubs::nextReturn('sql_save', 1);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('db_affected_rows')) {
|
|
function db_affected_rows($db_conn = false) {
|
|
return CactiStubs::nextReturn('db_affected_rows', 1);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('rrdtool_function_graph')) {
|
|
function rrdtool_function_graph($local_graph_id, $rra_id, $graph_data_array, $rrdtool_pipe = false, &$xport_meta = [], $user = 0) {
|
|
CactiStubs::record('rrdtool_function_graph', (string) $local_graph_id);
|
|
|
|
// A one-pixel PNG stands in for the rendered graph.
|
|
return base64_decode('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==', true);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('get_timespan')) {
|
|
function get_timespan(&$timespan, $time, $span, $first_weekdayid) {
|
|
$timespan['begin_now'] = $time - 86400;
|
|
$timespan['end_now'] = $time;
|
|
}
|
|
}
|
|
|
|
if (!function_exists('read_user_setting')) {
|
|
function read_user_setting($config_name, $default = false, $force = false, $user = 0) {
|
|
return CactiStubs::nextReturn('read_user_setting', $default);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('get_selected_theme')) {
|
|
function get_selected_theme() {
|
|
return 'modern';
|
|
}
|
|
}
|
|
|
|
if (!function_exists('mailer')) {
|
|
function mailer($from, $to, $cc = '', $bcc = '', $replyto = '', $subject = '', $body = '', $body_text = '', $attachments = null, $headers = [], $html = true) {
|
|
CactiStubs::$mail[] = [
|
|
'to' => is_array($to) ? implode(',', $to) : (string) $to,
|
|
'bcc' => is_array($bcc) ? implode(',', $bcc) : (string) $bcc,
|
|
'subject' => (string) $subject,
|
|
];
|
|
|
|
return CactiStubs::nextReturn('mailer', '');
|
|
}
|
|
}
|
|
|
|
if (!function_exists('cacti_snmp_send')) {
|
|
function cacti_snmp_send($hostname, $version, $community, $oid, $value, $type = 's') {
|
|
CactiStubs::record('cacti_snmp_send', (string) $oid);
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (!function_exists('debounce_run_notification')) {
|
|
function debounce_run_notification($id, $frequency = 60, ...$args) {
|
|
CactiStubs::record('debounce_run_notification', (string) $id);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('array_rekey')) {
|
|
function array_rekey($array, $key, $key_value) {
|
|
$ret_array = [];
|
|
|
|
if (is_array($array)) {
|
|
foreach ($array as $item) {
|
|
$item_key = $item[$key];
|
|
|
|
if (is_array($key_value)) {
|
|
foreach ($key_value as $value) {
|
|
$ret_array[$item_key][$value] = $item[$value];
|
|
}
|
|
} else {
|
|
$ret_array[$item_key] = $item[$key_value];
|
|
}
|
|
}
|
|
}
|
|
|
|
return $ret_array;
|
|
}
|
|
}
|
|
|
|
if (!function_exists('clean_up_name')) {
|
|
function clean_up_name($string) {
|
|
$string = preg_replace('/[\s\.]+/', '_', $string);
|
|
$string = preg_replace('/[^a-zA-Z0-9_]+/', '', $string);
|
|
|
|
return preg_replace('/_{2,}/', '_', $string);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('plugin_maint_check_cacti_host')) {
|
|
function plugin_maint_check_cacti_host($host_id) {
|
|
return CactiStubs::nextReturn('plugin_maint_check_cacti_host', false);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('api_plugin_is_enabled')) {
|
|
function api_plugin_is_enabled($plugin) {
|
|
return CactiStubs::nextReturn('api_plugin_is_enabled', false);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('api_plugin_hook')) {
|
|
function api_plugin_hook($name, $data = '') {
|
|
CactiStubs::record('api_plugin_hook', $name);
|
|
|
|
return $data;
|
|
}
|
|
}
|
|
|
|
if (!function_exists('api_plugin_register_hook')) {
|
|
function api_plugin_register_hook($name, $hook, $function, $file, $status = '') {
|
|
CactiStubs::record('api_plugin_register_hook', $hook, ['name' => $name, 'function' => $function, 'file' => $file]);
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (!function_exists('api_plugin_register_realm')) {
|
|
function api_plugin_register_realm($name, $files, $title, $navigate = 0) {
|
|
CactiStubs::record('api_plugin_register_realm', $files, ['name' => $name, 'title' => $title]);
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (!function_exists('api_plugin_enable_hooks')) {
|
|
function api_plugin_enable_hooks($name) {
|
|
CactiStubs::record('api_plugin_enable_hooks', $name);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('get_current_page')) {
|
|
function get_current_page() {
|
|
return CactiStubs::nextReturn('get_current_page', '');
|
|
}
|
|
}
|
|
|
|
if (!function_exists('api_user_realm_auth')) {
|
|
function api_user_realm_auth($filename = '') {
|
|
return CactiStubs::nextReturn('api_user_realm_auth', true);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('raise_message')) {
|
|
function raise_message($message_id, $message = '', $level = 0) {
|
|
CactiStubs::record('raise_message', (string) $message_id);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('rrdtool_execute')) {
|
|
function rrdtool_execute($command, $log_to_stdout = false, $output_flag = 1, $rrdtool_pipe = false, $logopt = 'WEBLOG') {
|
|
CactiStubs::record('rrdtool_execute', $command);
|
|
|
|
return CactiStubs::nextReturn('rrdtool_execute', '', $command);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('rrdtool_function_interface_speed')) {
|
|
function rrdtool_function_interface_speed($data_local) {
|
|
return CactiStubs::nextReturn('rrdtool_function_interface_speed', 0);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('substitute_snmp_query_data')) {
|
|
function substitute_snmp_query_data($value, $host_id, $snmp_query_id, $snmp_index) {
|
|
CactiStubs::record('substitute_snmp_query_data', (string) $value, [$host_id, $snmp_query_id, $snmp_index]);
|
|
|
|
return CactiStubs::nextReturn('substitute_snmp_query_data', $value);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('get_timeinstate')) {
|
|
function get_timeinstate($host) {
|
|
return CactiStubs::nextReturn('get_timeinstate', '1 day');
|
|
}
|
|
}
|
|
|
|
if (!function_exists('get_daysfromtime')) {
|
|
function get_daysfromtime($timestamp) {
|
|
return CactiStubs::nextReturn('get_daysfromtime', '1 day');
|
|
}
|
|
}
|
|
|
|
if (!function_exists('number_format_i18n')) {
|
|
function number_format_i18n($number, $decimals = 0, $baseu = 1000) {
|
|
return number_format((float) $number, $decimals < 0 ? 0 : (int) $decimals);
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
// Device states, from Cacti include/global_constants.php.
|
|
foreach (['HOST_UNKNOWN' => 0, 'HOST_DOWN' => 1, 'HOST_RECOVERING' => 2, 'HOST_UP' => 3, 'HOST_ERROR' => 4] as $name => $value) {
|
|
if (!defined($name)) {
|
|
define($name, $value);
|
|
}
|
|
}
|
|
|
|
// rrdtool output modes, from Cacti include/global_constants.php.
|
|
foreach (['RRDTOOL_OUTPUT_NULL' => 0, 'RRDTOOL_OUTPUT_STDOUT' => 1, 'RRDTOOL_OUTPUT_STDERR' => 2,
|
|
'RRDTOOL_OUTPUT_GRAPH_DATA' => 3, 'RRDTOOL_OUTPUT_BOOLEAN' => 4,
|
|
'RRDTOOL_OUTPUT_RETURN_STDERR' => 5] as $name => $value) {
|
|
if (!defined($name)) {
|
|
define($name, $value);
|
|
}
|
|
}
|
|
|
|
if (!defined('CACTI_DATE_TIME_FORMAT')) {
|
|
define('CACTI_DATE_TIME_FORMAT', 'Y-m-d H:i:s');
|
|
}
|
|
|
|
if (!defined('CACTI_PATH_BASE')) {
|
|
define('CACTI_PATH_BASE', $GLOBALS['config']['base_path']);
|
|
}
|
|
|
|
if (!function_exists('plugin_test_read_source')) {
|
|
/**
|
|
* Read a plugin source file's raw contents, relative to the plugin root.
|
|
*
|
|
* @param string $relative_file Plugin file, relative to the plugin root.
|
|
*
|
|
* @return string
|
|
*/
|
|
function plugin_test_read_source($relative_file) {
|
|
$path = realpath(__DIR__ . '/../' . $relative_file);
|
|
|
|
if ($path === false) {
|
|
throw new RuntimeException("Unable to resolve required file: {$relative_file}");
|
|
}
|
|
|
|
$contents = file_get_contents($path);
|
|
|
|
if ($contents === false) {
|
|
throw new RuntimeException("Unable to read required file: {$relative_file}");
|
|
}
|
|
|
|
return $contents;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Load a plugin source file at global scope.
|
|
*
|
|
* Several plugin files (includes/arrays.php in particular) define their data
|
|
* as file-scope variables that the rest of the plugin reads as globals, and
|
|
* they read $config while doing so. Requiring them from inside a method would
|
|
* make both halves of that method-local, so the require happens here and any
|
|
* variable the file introduced is published to $GLOBALS.
|
|
*
|
|
* @param string $path Absolute path to the file.
|
|
*
|
|
* @return void
|
|
*/
|
|
function thold_test_load($path) {
|
|
global $config;
|
|
|
|
$__before = get_defined_vars();
|
|
|
|
require_once $path;
|
|
|
|
foreach (get_defined_vars() as $__name => $__value) {
|
|
if (!array_key_exists($__name, $__before) && strncmp($__name, '__', 2) !== 0) {
|
|
$GLOBALS[$__name] = $__value;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Load a plugin source file that only assigns file-scope variables (no
|
|
* function/class declarations), publishing them to $GLOBALS the same way as
|
|
* thold_test_load().
|
|
*
|
|
* includes/arrays.php is also included with a plain include() (not
|
|
* include_once()) from several places in includes/functions.php itself (e.g.
|
|
* thold_log()), keyed off $config['base_path']. Once any test exercises one
|
|
* of those call sites, PHP's include-once registry considers the file
|
|
* already included: a later thold_test_load() (require_once) on the same
|
|
* resolved path silently no-ops and never (re)publishes $thold_types. Using
|
|
* a plain require() here sidesteps that registry entirely, so re-running it
|
|
* is always safe and cheap for a file that just assigns arrays.
|
|
*
|
|
* @param string $path Absolute path to the file.
|
|
*
|
|
* @return void
|
|
*/
|
|
function thold_test_load_always($path) {
|
|
global $config;
|
|
|
|
$__before = get_defined_vars();
|
|
|
|
require $path;
|
|
|
|
foreach (get_defined_vars() as $__name => $__value) {
|
|
if (!array_key_exists($__name, $__before) && strncmp($__name, '__', 2) !== 0) {
|
|
$GLOBALS[$__name] = $__value;
|
|
}
|
|
}
|
|
}
|