mirror of
https://github.com/Cacti/plugin_monitor.git
synced 2026-10-23 03:26:42 +09:00
Refactor codebase for PSR12 compliance and modernization (#202)
* PSR12 - First run Rename functions to match PSR12 requirements * PSR12 run 1 - Change tabs to spaces - add consts * reduce cognetive complexity scores based on PSR12 and sonar scans * Split poller_monitor with helper file * update docblocks * code reorginization Breaking up some of the large files * modernize js Replaced legacy var with const/let. Switched loose checks to strict (===, !==, strict typeof checks). Added default param: applyFilter(action = ''). Used template literals for URL/query string assembly. Converted many callbacks to arrow functions and shorthand methods. Removed one duplicate object key in saveFilter payload (trim was defined twice with same value). Kept existing flow, DOM selectors, action names, and endpoints unchanged. * Update monitor.js Applied the Sonar-requested cleanups in monitor.js: * remove unused variables * remove unused variables * Update copilot-instructions.md * PSR12 formatting * Update db_functions.php * refactor functions Refactor rending function and Ajax call functions Lowe cognetive complexity prepare for easier testing * Add missing docblocks * Apply typing * remove checks for min php version * correct installation errors after PSR12 * try iinstall fix one more time * . * Update monitor_controller.php * Update monitor_controller.php * Update monitor_render.php * fix typing errors * apply php cs-fixer updates * missed 2 commits * Update js/monitor.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update js/monitor.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update copilot-instructions.md --------- Co-authored-by: TheWitness <thewitness@cacti.net> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
15 files changed
+4367
-3513
No files matched your search
+70
-111
@@ -4,153 +4,112 @@
|
||||
|
||||
When generating code for this repository:
|
||||
|
||||
1. **Version Compatibility**: Respect versions and compatibility declared by this plugin and CI.
|
||||
2. **Context Files**: If `.github/copilot/*` files are added later, prioritize them first.
|
||||
3. **Codebase Patterns**: When no explicit guidance exists, follow established patterns in this repository.
|
||||
4. **Architectural Consistency**: Preserve the current monolithic, procedural Cacti plugin architecture.
|
||||
5. **Code Quality**: Prioritize maintainability, security, performance, and testability in ways already present in this codebase.
|
||||
1. **Version Compatibility First**: Honor plugin and CI version constraints before all style preferences.
|
||||
2. **Repository Context Files**: Prioritize `.github/copilot/*` docs if they are added later.
|
||||
3. **Agent Profiles as Secondary Context**: Reuse conventions from `.github/agents/*.md` when applicable.
|
||||
4. **Pattern Matching Over Reinvention**: Mirror existing plugin patterns in the same file/flow.
|
||||
5. **Architectural Consistency**: Keep the plugin procedural and Cacti-native.
|
||||
|
||||
## Technology Version Detection
|
||||
## Verified Runtime and Compatibility
|
||||
|
||||
Before generating code, detect and honor exact versions from repository metadata:
|
||||
Use only capabilities compatible with observed project metadata:
|
||||
|
||||
- **Plugin metadata**: `INFO`
|
||||
- **Plugin metadata (`INFO`)**
|
||||
- `name = monitor`
|
||||
- `version = 2.8`
|
||||
- `compat = 1.2.15` (Cacti compatibility)
|
||||
- `compat = 1.2.15`
|
||||
- `requires = thold:1.2.1`
|
||||
- **CI runtime matrix**: `.github/workflows/plugin-ci-workflow.yml`
|
||||
- **CI matrix (`.github/workflows/plugin-ci-workflow.yml`)**
|
||||
- PHP: `8.1`, `8.2`, `8.3`, `8.4`
|
||||
- OS: `ubuntu-latest`
|
||||
- MariaDB service: `10.6`
|
||||
- **Language/frameworks observed**:
|
||||
- PHP plugin code (`setup.php`, `monitor.php`, `poller_monitor.php`)
|
||||
- CSS themes (`monitor.css`, `themes/*/monitor.css`)
|
||||
- GitHub Actions workflow YAML
|
||||
- **Observed technologies**
|
||||
- Procedural PHP plugin files
|
||||
- CSS theme overlays in `themes/*/monitor.css`
|
||||
- gettext localization (`locales/po/*.po`, `locales/LC_MESSAGES/*.mo`)
|
||||
- GitHub Actions integration checks
|
||||
|
||||
Do not introduce APIs or syntax incompatible with the supported Cacti/plugin environment and CI matrix.
|
||||
Do not introduce syntax or APIs that could fail under these versions.
|
||||
|
||||
## Context Files
|
||||
## Architecture and File Responsibilities
|
||||
|
||||
If present in future, prioritize `.github/copilot` files in this order:
|
||||
This is a single Cacti plugin with procedural flows split by responsibility:
|
||||
|
||||
- `architecture.md`
|
||||
- `tech-stack.md`
|
||||
- `coding-standards.md`
|
||||
- `folder-structure.md`
|
||||
- `exemplars.md`
|
||||
- `setup.php`: plugin lifecycle, hook registration, config arrays/settings, install/upgrade table management.
|
||||
- `monitor.php`: web entrypoint/bootstrap, includes, session/request setup.
|
||||
- `monitor_controller.php`: action flow, filter handling, page orchestration.
|
||||
- `monitor_render.php`: dashboard/group rendering and view-specific output.
|
||||
- `db_functions.php`: SQL filter/join helpers and status/device query utilities.
|
||||
- `poller_monitor.php`: CLI poller entrypoint (`--help`, `--version`, `--debug`).
|
||||
- `poller_functions.php`: poller helper logic (uptime checks, notifications, email payload building).
|
||||
|
||||
If these files do not exist, use repository patterns directly.
|
||||
Avoid OO/framework refactors unless explicitly requested.
|
||||
|
||||
## Architecture and Boundaries (Observed)
|
||||
## Coding Patterns to Preserve
|
||||
|
||||
This repository is a **single Cacti plugin** with procedural PHP entrypoints and Cacti hook integration.
|
||||
### Naming and Structure
|
||||
|
||||
- **Plugin lifecycle and hooks**: `setup.php`
|
||||
- Registration via `api_plugin_register_hook()` and `api_plugin_register_realm()`.
|
||||
- Upgrade/install logic via `plugin_monitor_install()`, `plugin_monitor_upgrade()`, `monitor_check_upgrade()`.
|
||||
- **Web UI controller/rendering**: `monitor.php`
|
||||
- Request routing by `action` switch.
|
||||
- Rendering and UI state via Cacti helper functions.
|
||||
- **CLI/poller processing**: `poller_monitor.php`
|
||||
- Argument parsing (`--help`, `--version`, `--force`, `--debug`).
|
||||
- Notification and uptime/reboot processing.
|
||||
- **Presentation assets**: `monitor.css`, `themes/*/monitor.css`, `sounds/`, `images/`.
|
||||
- **Localization assets**: gettext `.po/.mo` files under `locales/`.
|
||||
- Use procedural functions with **lowerCamelCase** naming, matching current core files.
|
||||
- Keep plugin hook callback names exactly synchronized between definitions and `api_plugin_register_hook()` registration strings.
|
||||
- Keep top-level entrypoints lightweight; place reusable logic in helper files.
|
||||
|
||||
Do not refactor this plugin into OO/framework patterns unless the existing code in this repository does so first.
|
||||
### Cacti Integration
|
||||
|
||||
## Codebase Scanning Instructions
|
||||
- Prefer Cacti APIs already used in this plugin:
|
||||
- Config/state: `read_config_option()`, `set_config_option()`, `read_user_setting()`, `set_user_setting()`
|
||||
- Request helpers: `get_request_var()`, `get_filter_request_var()`, `get_nfilter_request_var()`, `set_request_var()`, `validateRequestVars()`
|
||||
- DB helpers: `db_fetch_assoc()`, `db_fetch_row_prepared()`, `db_fetch_cell_prepared()`, `db_execute_prepared()`
|
||||
- Plugin hooks/realms: `api_plugin_register_hook()`, `api_plugin_register_realm()`
|
||||
- Use gettext calls with the `monitor` domain for user-facing strings: `__('Text', 'monitor')`.
|
||||
|
||||
For any new change:
|
||||
### Data and Schema Safety
|
||||
|
||||
1. Find similar logic in the same entrypoint type (`setup.php` for hooks/config, `monitor.php` for UI routing/rendering, `poller_monitor.php` for CLI/poller flows).
|
||||
2. Match these patterns exactly:
|
||||
- Function naming: `monitor_*`, `plugin_monitor_*`
|
||||
- Procedural flow with top-level includes and switch routing
|
||||
- Cacti helper/database APIs (`db_fetch_*`, `db_execute*`, `read_config_option`, `set_config_option`)
|
||||
- Localization calls: `__('Text', 'monitor')`
|
||||
3. Reuse existing request handling and sanitization helpers before adding any new input handling.
|
||||
4. Prefer existing table names and schema migration style in `monitor_check_upgrade()` and related setup functions.
|
||||
5. Avoid introducing new architectural abstractions not currently used.
|
||||
- Keep schema evolution in existing setup/upgrade flows (table creation/alter logic in setup lifecycle functions).
|
||||
- Reuse existing table names and avoid introducing parallel schema variants.
|
||||
- Prefer prepared DB calls when dynamic values are present.
|
||||
|
||||
## Code Quality Standards (Evidence-Based)
|
||||
## Quality Expectations
|
||||
|
||||
### Maintainability
|
||||
|
||||
- Keep procedural style and naming consistent with existing files.
|
||||
- Keep related behavior grouped by responsibility (install/upgrade/hooks in `setup.php`; UI rendering in `monitor.php`; poller logic in `poller_monitor.php`).
|
||||
- Prefer small helper functions as seen throughout the codebase.
|
||||
- Keep changes localized to the appropriate responsibility file.
|
||||
- Favor small helper extractions for complex branches (pattern used in `poller_functions.php`).
|
||||
- Do not rename public/plugin callback functions unless all call sites and hook strings are updated.
|
||||
|
||||
### Security
|
||||
|
||||
- Follow current input-handling patterns:
|
||||
- `get_request_var()`, `get_nfilter_request_var()`, `get_filter_request_var()`, `set_request_var()`
|
||||
- `validate_request_vars()` where appropriate
|
||||
- Escape output using existing helpers such as `html_escape()` for HTML contexts.
|
||||
- Use prepared database calls where parameters are dynamic (`db_fetch_*_prepared`, `db_execute_prepared`) following existing usage.
|
||||
- Continue current request-validation patterns before consuming request values.
|
||||
- Escape HTML output with existing helpers (e.g., `html_escape()`).
|
||||
- Avoid direct string interpolation for dynamic SQL parameters when prepared variants exist.
|
||||
|
||||
### Performance
|
||||
|
||||
- Match existing data-access style: targeted SQL queries and batched operations.
|
||||
- Preserve existing poller timing/stat collection behavior in `poller_monitor.php`.
|
||||
- Avoid adding expensive repeated queries inside loops when existing code already provides reusable query patterns.
|
||||
- Avoid repeated expensive queries inside loops.
|
||||
- Follow current query-shaping patterns (precompute lists/maps, then iterate).
|
||||
- Preserve current poller stat logging behavior and timing model.
|
||||
|
||||
### Testability
|
||||
### Documentation
|
||||
|
||||
- Keep logic in discrete functions so behavior can be linted, statically analyzed, and integration-tested as in CI.
|
||||
- Preserve CLI flags and deterministic output patterns used by workflow checks.
|
||||
- Keep function docblocks descriptive where present, especially in `poller_functions.php`.
|
||||
- Keep inline comments concise and only where intent is non-obvious.
|
||||
- Do not add boilerplate comments for trivial statements.
|
||||
|
||||
## Documentation Requirements
|
||||
## Validation and CI Alignment
|
||||
|
||||
Documentation level in this repository is **Standard**:
|
||||
Before finalizing substantial PHP changes:
|
||||
|
||||
- File-level header blocks are consistently present in PHP and workflow files.
|
||||
- Inline comments are concise and purpose-driven.
|
||||
- Follow existing style: do not over-document trivial lines.
|
||||
- Update `CHANGELOG.md` style only when project maintainers require release note updates.
|
||||
1. Run PHP syntax checks (`php -l`) on modified plugin files.
|
||||
2. Ensure compatibility with Cacti-driven lint/style checks used in CI (`lint`, `phpcsfixer` scripts run from Cacti workspace).
|
||||
3. Preserve integration behavior expected by CI:
|
||||
- Plugin install/enable via Cacti CLI
|
||||
- Poller execution path and monitor stats logging
|
||||
|
||||
## Testing Approach (Observed)
|
||||
Do not add a new local unit-test framework unless requested.
|
||||
|
||||
This repository relies on **integration + static checks** via GitHub Actions:
|
||||
## Scope Rules for Future Changes
|
||||
|
||||
- PHP syntax lint (`php -l` over plugin files)
|
||||
- Composer-based lint/style checks from Cacti workspace (`lint`, `phpcsfixer` scripts)
|
||||
- Runtime integration checks by installing Cacti + plugin and running poller
|
||||
- No repository-local unit test suite is currently present
|
||||
- Prefer minimal, surgical updates over broad rewrites.
|
||||
- Keep CSS/theme updates limited to existing theme file layout.
|
||||
- Keep localization changes aligned to existing gettext workflow/files.
|
||||
- If guidance conflicts, prefer behavior already validated in runtime entrypoints and CI workflow.
|
||||
|
||||
When generating code:
|
||||
|
||||
- Ensure code is syntactically valid PHP.
|
||||
- Keep style and lint compatibility with current Cacti-driven CI steps.
|
||||
- Do not invent a new test framework in this plugin unless requested.
|
||||
|
||||
## PHP-Specific Guidelines
|
||||
|
||||
- Maintain procedural PHP structure and Cacti plugin API usage.
|
||||
- Keep includes, globals, and helper calls consistent with existing patterns.
|
||||
- Match array formatting and control-flow style used in current files.
|
||||
- Continue using gettext domain `'monitor'` for user-facing strings.
|
||||
- Preserve compatibility with CI-validated PHP versions and Cacti/plugin constraints.
|
||||
|
||||
## Versioning and Change Tracking
|
||||
|
||||
- Follow existing changelog conventions in `CHANGELOG.md` (sectioned by release, `issue#` / `feature#` bullets).
|
||||
- Treat plugin version metadata in `INFO` as the authoritative plugin version declaration.
|
||||
|
||||
## General Best Practices for This Repository
|
||||
|
||||
- Prioritize consistency with existing code over introducing newer external patterns.
|
||||
- Reuse existing Cacti APIs and plugin hooks instead of custom abstractions.
|
||||
- Keep CSS/theme changes aligned with current theme folder structure.
|
||||
- Keep localization updates aligned with existing gettext files and domain usage.
|
||||
- If uncertain, mirror nearby code patterns in the same file first.
|
||||
|
||||
## Project-Specific Guidance
|
||||
|
||||
- Scan relevant files before generating code; do not assume patterns from unrelated projects.
|
||||
- Respect current architectural boundaries:
|
||||
- Hook/config lifecycle in `setup.php`
|
||||
- UI/rendering workflow in `monitor.php`
|
||||
- Poller/notification workflow in `poller_monitor.php`
|
||||
- When conflicts arise, prefer patterns that are currently active in top-level runtime paths and CI-validated flows.
|
||||
- Always prioritize compatibility and consistency with this repository over external “best practice” rewrites.
|
||||
@@ -0,0 +1,314 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| 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/ |
|
||||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/**
|
||||
* Build thold SQL predicate based on selected monitor status filter.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function getTholdWhere(): string {
|
||||
if (get_request_var('status') == '2') { // breached
|
||||
return "(td.thold_enabled = 'on'
|
||||
AND (td.thold_alert != 0 OR td.bl_alert > 0))";
|
||||
} else { // triggered
|
||||
return "(td.thold_enabled='on'
|
||||
AND ((td.thold_alert != 0 AND td.thold_fail_count >= td.thold_fail_trigger)
|
||||
OR (td.bl_alert > 0 AND td.bl_fail_count >= td.bl_fail_trigger)))";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get host ids currently associated with triggered/breached thresholds.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function checkTholds(): array {
|
||||
$thold_hosts = [];
|
||||
|
||||
if (api_plugin_is_enabled('thold')) {
|
||||
return array_rekey(
|
||||
db_fetch_assoc('SELECT DISTINCT dl.host_id
|
||||
FROM thold_data AS td
|
||||
INNER JOIN data_local AS dl
|
||||
ON td.local_data_id=dl.id
|
||||
WHERE ' . getTholdWhere()),
|
||||
'host_id',
|
||||
'host_id'
|
||||
);
|
||||
}
|
||||
|
||||
return $thold_hosts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append an IN-clause fragment to an existing SQL where string.
|
||||
*
|
||||
* @param string $sql_where SQL where fragment, updated in place.
|
||||
* @param string $sql_join Join token used between predicates (e.g. AND/OR).
|
||||
* @param string $sql_field Field name to compare with IN list.
|
||||
* @param string $sql_data Comma-delimited values for the IN list.
|
||||
* @param string $sql_suffix Optional suffix appended inside predicate.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function renderGroupConcat(string &$sql_where, string $sql_join, string $sql_field, string $sql_data, string $sql_suffix = ''): void {
|
||||
// Remove empty entries if something was returned
|
||||
if (!empty($sql_data)) {
|
||||
$sql_data = trim(str_replace(',,', ',', $sql_data), ',');
|
||||
|
||||
if (!empty($sql_data)) {
|
||||
$sql_where .= ($sql_where != '' ? $sql_join : '') . "($sql_field IN($sql_data) $sql_suffix)";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build core monitor host query join/where fragments from current filters.
|
||||
*
|
||||
* @param string $sql_where SQL where fragment, updated in place.
|
||||
* @param string $sql_join SQL join fragment, updated in place.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function renderWhereJoin(string &$sql_where, string &$sql_join): void {
|
||||
if (get_request_var('crit') > 0) {
|
||||
$awhere = 'h.monitor_criticality >= ' . get_request_var('crit');
|
||||
} else {
|
||||
$awhere = '';
|
||||
}
|
||||
|
||||
if (get_request_var('grouping') == 'site') {
|
||||
if (get_request_var('site') > 0) {
|
||||
$awhere .= ($awhere == '' ? '' : ' AND ') . 'h.site_id = ' . get_request_var('site');
|
||||
} elseif (get_request_var('site') == -2) {
|
||||
$awhere .= ($awhere == '' ? '' : ' AND ') . ' h.site_id = 0';
|
||||
}
|
||||
}
|
||||
|
||||
if (get_request_var('rfilter') != '') {
|
||||
$awhere .= ($awhere == '' ? '' : ' AND ') . " h.description RLIKE '" . get_request_var('rfilter') . "'";
|
||||
}
|
||||
|
||||
if (get_request_var('grouping') == 'tree') {
|
||||
if (get_request_var('tree') > 0) {
|
||||
$hlist = db_fetch_cell_prepared(
|
||||
'SELECT GROUP_CONCAT(DISTINCT host_id)
|
||||
FROM graph_tree_items AS gti
|
||||
INNER JOIN host AS h
|
||||
ON h.id = gti.host_id
|
||||
WHERE host_id > 0
|
||||
AND graph_tree_id = ?
|
||||
AND h.deleted = ""',
|
||||
[get_request_var('tree')]
|
||||
);
|
||||
|
||||
renderGroupConcat($awhere, ' AND ', 'h.id', $hlist);
|
||||
} elseif (get_request_var('tree') == -2) {
|
||||
$hlist = db_fetch_cell('SELECT GROUP_CONCAT(DISTINCT h.id)
|
||||
FROM host AS h
|
||||
LEFT JOIN (SELECT DISTINCT host_id FROM graph_tree_items WHERE host_id > 0) AS gti
|
||||
ON h.id = gti.host_id
|
||||
WHERE gti.host_id IS NULL
|
||||
AND h.deleted = ""');
|
||||
|
||||
renderGroupConcat($awhere, ' AND ', 'h.id', $hlist);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($awhere)) {
|
||||
$awhere = ' AND ' . $awhere;
|
||||
}
|
||||
|
||||
if (get_request_var('status') == '0') {
|
||||
$sql_join = '';
|
||||
$sql_where = 'WHERE h.disabled = ""
|
||||
AND h.monitor = "on"
|
||||
AND h.status < 3
|
||||
AND h.deleted = ""
|
||||
AND (h.availability_method > 0
|
||||
OR h.snmp_version > 0
|
||||
OR (h.cur_time >= h.monitor_warn AND h.monitor_warn > 0)
|
||||
OR (h.cur_time >= h.monitor_alert AND h.monitor_alert > 0)
|
||||
)' . $awhere;
|
||||
} elseif (get_request_var('status') == '1' || get_request_var('status') == 2) {
|
||||
$sql_join = 'LEFT JOIN thold_data AS td ON td.host_id=h.id';
|
||||
|
||||
$sql_where = 'WHERE h.disabled = ""
|
||||
AND h.monitor = "on"
|
||||
AND h.deleted = ""
|
||||
AND (h.status < 3
|
||||
OR ' . getTholdWhere() . '
|
||||
OR ((h.availability_method > 0 OR h.snmp_version > 0)
|
||||
AND ((h.cur_time > h.monitor_warn AND h.monitor_warn > 0)
|
||||
OR (h.cur_time > h.monitor_alert AND h.monitor_alert > 0)))
|
||||
)' . $awhere;
|
||||
} elseif (get_request_var('status') == -1) {
|
||||
$sql_join = 'LEFT JOIN thold_data AS td ON td.host_id=h.id';
|
||||
|
||||
$sql_where = 'WHERE h.disabled = ""
|
||||
AND h.monitor = "on"
|
||||
AND h.deleted = ""
|
||||
AND (h.availability_method > 0 OR h.snmp_version > 0
|
||||
OR ((td.thold_enabled="on" AND td.thold_alert > 0)
|
||||
OR td.id IS NULL)
|
||||
)' . $awhere;
|
||||
} elseif (get_request_var('status') == -2) {
|
||||
$sql_join = 'LEFT JOIN thold_data AS td ON td.host_id=h.id';
|
||||
|
||||
$sql_where = 'WHERE h.disabled = ""
|
||||
AND h.deleted = ""' . $awhere;
|
||||
} elseif (get_request_var('status') == -3) {
|
||||
$sql_join = 'LEFT JOIN thold_data AS td ON td.host_id=h.id';
|
||||
|
||||
$sql_where = 'WHERE h.disabled = ""
|
||||
AND h.monitor = ""
|
||||
AND h.deleted = ""' . $awhere;
|
||||
} else {
|
||||
$sql_join = 'LEFT JOIN thold_data AS td ON td.host_id=h.id';
|
||||
|
||||
$sql_where = 'WHERE (h.disabled = ""
|
||||
AND h.deleted = ""
|
||||
AND td.id IS NULL)' . $awhere;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return host ids that are down/triggered and visible to current user.
|
||||
*
|
||||
* @param bool $prescan Whether to use prescan severity threshold.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function getHostsDownOrTriggeredByPermission(bool $prescan): array {
|
||||
global $render_style;
|
||||
$PreScanValue = 2;
|
||||
|
||||
if ($prescan) {
|
||||
$PreScanValue = 3;
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
if (get_request_var('crit') > 0) {
|
||||
$sql_add_where = 'monitor_criticality >= ' . get_request_var('crit');
|
||||
} else {
|
||||
$sql_add_where = '';
|
||||
}
|
||||
|
||||
if (get_request_var('grouping') == 'tree') {
|
||||
if (get_request_var('tree') > 0) {
|
||||
$devices = db_fetch_cell_prepared(
|
||||
'SELECT GROUP_CONCAT(DISTINCT host_id) AS hosts
|
||||
FROM graph_tree_items AS gti
|
||||
INNER JOIN host AS h
|
||||
WHERE host_id > 0
|
||||
AND h.deleted = ""
|
||||
AND graph_tree_id = ?',
|
||||
[get_request_var('tree')]
|
||||
);
|
||||
|
||||
renderGroupConcat($sql_add_where, ' OR ', 'h.id', $devices, 'AND h.status < 2');
|
||||
}
|
||||
}
|
||||
|
||||
if (get_request_var('status') > 0) {
|
||||
$triggered = db_fetch_cell('SELECT GROUP_CONCAT(DISTINCT host_id) AS hosts
|
||||
FROM host AS h
|
||||
INNER JOIN thold_data AS td
|
||||
ON td.host_id = h.id
|
||||
WHERE ' . getTholdWhere() . '
|
||||
AND h.deleted = ""');
|
||||
|
||||
renderGroupConcat($sql_add_where, ' OR ', 'h.id', $triggered, 'AND h.status > 1');
|
||||
|
||||
$_SESSION['monitor_triggered'] = array_rekey(
|
||||
db_fetch_assoc('SELECT td.host_id, COUNT(DISTINCT td.id) AS triggered
|
||||
FROM thold_data AS td
|
||||
INNER JOIN host AS h
|
||||
ON td.host_id = h.id
|
||||
WHERE ' . getTholdWhere() . '
|
||||
AND h.deleted = ""
|
||||
GROUP BY td.host_id'),
|
||||
'host_id',
|
||||
'triggered'
|
||||
);
|
||||
}
|
||||
|
||||
$sql_where = "h.monitor = 'on'
|
||||
AND h.disabled = ''
|
||||
AND h.deleted = ''
|
||||
AND ((h.status < " . $PreScanValue . ' AND (h.availability_method > 0 OR h.snmp_version > 0)) ' .
|
||||
($sql_add_where != '' ? ' OR (' . $sql_add_where . '))' : ')');
|
||||
|
||||
// do a quick loop through to pull the hosts that are down
|
||||
$hosts = get_allowed_devices($sql_where);
|
||||
|
||||
if (cacti_sizeof($hosts)) {
|
||||
foreach ($hosts as $host) {
|
||||
$result[] = $host['id'];
|
||||
sort($result);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return non-tree monitor hosts after applying current filters.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function getHostNonTreeArray(): array {
|
||||
$leafs = [];
|
||||
|
||||
$sql_where = '';
|
||||
$sql_join = '';
|
||||
|
||||
renderWhereJoin($sql_where, $sql_join);
|
||||
|
||||
$hierarchy = db_fetch_assoc("SELECT DISTINCT
|
||||
h.*, gti.title, gti.host_id, gti.host_grouping_type, gti.graph_tree_id
|
||||
FROM host AS h
|
||||
LEFT JOIN graph_tree_items AS gti
|
||||
ON h.id=gti.host_id
|
||||
$sql_join
|
||||
$sql_where
|
||||
AND gti.graph_tree_id IS NULL
|
||||
ORDER BY h.description");
|
||||
|
||||
if (cacti_sizeof($hierarchy) > 0) {
|
||||
$leafs = [];
|
||||
$branchleafs = 0;
|
||||
|
||||
foreach ($hierarchy as $leaf) {
|
||||
$leafs[$branchleafs] = $leaf;
|
||||
$branchleafs++;
|
||||
}
|
||||
}
|
||||
|
||||
return $leafs;
|
||||
}
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
|
||||
+354
@@ -0,0 +1,354 @@
|
||||
let refreshMSeconds = 99999999;
|
||||
let myTimer;
|
||||
|
||||
const monitorCfg = globalThis.monitorPageConfig || {};
|
||||
const mbColor = monitorCfg.mbColor || '';
|
||||
const monitorFont = monitorCfg.monitorFont || '10px';
|
||||
const dozoomRefresh = Boolean(monitorCfg.doZoomRefresh);
|
||||
const monitorMessages = monitorCfg.messages || {};
|
||||
const monitorNewForm = monitorCfg.newForm || '';
|
||||
const monitorNewTitle = monitorCfg.newTitle || '';
|
||||
|
||||
function setZoomErrorBackgrounds() {
|
||||
if (mbColor !== '') {
|
||||
$('.monitor_container').css('background-color', mbColor);
|
||||
$('.cactiConsoleContentArea').css('background-color', mbColor);
|
||||
}
|
||||
}
|
||||
|
||||
function setIntervalX(callback, delay, repetitions) {
|
||||
let x = 0;
|
||||
const intervalID = globalThis.setInterval(() => {
|
||||
callback();
|
||||
if (++x === repetitions) {
|
||||
globalThis.clearInterval(intervalID);
|
||||
setZoomErrorBackgrounds();
|
||||
}
|
||||
}, delay);
|
||||
}
|
||||
|
||||
if (mbColor === '') {
|
||||
$('.monitor_container').css('background-color', '');
|
||||
$('.cactiConsoleContentArea').css('background-color', '');
|
||||
} else {
|
||||
let monoe = false;
|
||||
|
||||
setZoomErrorBackgrounds();
|
||||
$('.monitor_errorzoom_title').css('font-size', monitorFont);
|
||||
|
||||
setIntervalX(() => {
|
||||
if (monoe) {
|
||||
if (mbColor !== '') {
|
||||
$('.monitor_container').css('background-color', '');
|
||||
$('.cactiConsoleContentArea').css('background-color', '');
|
||||
}
|
||||
|
||||
monoe = false;
|
||||
} else {
|
||||
setZoomErrorBackgrounds();
|
||||
monoe = true;
|
||||
}
|
||||
}, 600, 8);
|
||||
}
|
||||
|
||||
function timeStep() {
|
||||
const value = Number($('#timer').html()) - 1;
|
||||
|
||||
if (value <= 0) {
|
||||
applyFilter('refresh');
|
||||
} else {
|
||||
$('#timer').html(value);
|
||||
// What is a second, well if you are an
|
||||
// imperial storm tropper, it's just a little more than a second.
|
||||
myTimer = setTimeout(timeStep, 1284);
|
||||
}
|
||||
}
|
||||
|
||||
function muteUnmuteAudio(mute) {
|
||||
if (mute) {
|
||||
$('audio').each(function() {
|
||||
this.pause();
|
||||
this.currentTime = 0;
|
||||
});
|
||||
} else if ($('#downhosts').val() === 'true') {
|
||||
$('audio').each(function() {
|
||||
this.play();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function closeTip() {
|
||||
$(document).tooltip('close');
|
||||
}
|
||||
|
||||
function applyFilter(action = '') {
|
||||
clearTimeout(myTimer);
|
||||
$('.mon_icon').unbind();
|
||||
|
||||
let strURL;
|
||||
|
||||
if (action === 'dashboard') {
|
||||
strURL = `monitor.php?action=dbchange&header=false&dashboard=${$('#dashboard').val()}`;
|
||||
} else {
|
||||
strURL = 'monitor.php?header=false';
|
||||
|
||||
if (action !== '') {
|
||||
strURL += `&action=${action}`;
|
||||
}
|
||||
|
||||
strURL += `&refresh=${$('#refresh').val()}`;
|
||||
strURL += `&grouping=${$('#grouping').val()}`;
|
||||
strURL += `&tree=${$('#tree').val()}`;
|
||||
strURL += `&site=${$('#site').val()}`;
|
||||
strURL += `&template=${$('#template').val()}`;
|
||||
strURL += `&view=${$('#view').val()}`;
|
||||
strURL += `&rows=${$('#rows').val()}`;
|
||||
strURL += `&crit=${$('#crit').val()}`;
|
||||
strURL += `&size=${$('#size').val()}`;
|
||||
strURL += `&trim=${$('#trim').val()}`;
|
||||
strURL += `&mute=${$('#mute').val()}`;
|
||||
strURL += `&rfilter=${base64_encode($('#rfilter').val())}`;
|
||||
strURL += `&status=${$('#status').val()}`;
|
||||
}
|
||||
|
||||
loadIt(strURL);
|
||||
}
|
||||
|
||||
function saveFilter() {
|
||||
const url = 'monitor.php?action=save&header=false';
|
||||
|
||||
const post = {
|
||||
dashboard: $('#dashboard').val(),
|
||||
refresh: $('#refresh').val(),
|
||||
grouping: $('#grouping').val(),
|
||||
tree: $('#tree').val(),
|
||||
site: $('#site').val(),
|
||||
template: $('#template').val(),
|
||||
view: $('#view').val(),
|
||||
rows: $('#rows').val(),
|
||||
crit: $('#crit').val(),
|
||||
rfilter: base64_encode($('#rfilter').val()),
|
||||
trim: $('#trim').val(),
|
||||
mute: $('#mute').val(),
|
||||
size: $('#size').val(),
|
||||
status: $('#status').val(),
|
||||
__csrf_magic: csrfMagicToken
|
||||
};
|
||||
|
||||
$.post(url, post).done(() => {
|
||||
$('#text').show().text(monitorMessages.filterSaved || '').fadeOut(2000);
|
||||
});
|
||||
}
|
||||
|
||||
function saveNewDashboard(action) {
|
||||
const dashboard = action === 'new' ? '-1' : $('#dashboard').val();
|
||||
const url = 'monitor.php?header=false';
|
||||
|
||||
const post = {
|
||||
action: 'saveDb',
|
||||
dashboard,
|
||||
name: $('#name').val(),
|
||||
refresh: $('#refresh').val(),
|
||||
grouping: $('#grouping').val(),
|
||||
tree: $('#tree').val(),
|
||||
site: $('#site').val(),
|
||||
template: $('#template').val(),
|
||||
view: $('#view').val(),
|
||||
rows: $('#rows').val(),
|
||||
crit: $('#crit').val(),
|
||||
rfilter: base64_encode($('#rfilter').val()),
|
||||
trim: $('#trim').val(),
|
||||
size: $('#size').val(),
|
||||
mute: $('#mute').val(),
|
||||
status: $('#status').val(),
|
||||
__csrf_magic: csrfMagicToken
|
||||
};
|
||||
|
||||
$('#newdialog').dialog('close');
|
||||
postIt(url, post);
|
||||
}
|
||||
|
||||
function removeDashboard() {
|
||||
const url = `monitor.php?action=remove&header=false&dashboard=${$('#dashboard').val()}`;
|
||||
loadIt(url);
|
||||
}
|
||||
|
||||
function loadIt(url) {
|
||||
if (typeof loadUrl === 'undefined') {
|
||||
loadPageNoHeader(url);
|
||||
} else {
|
||||
loadUrl({ url });
|
||||
}
|
||||
}
|
||||
|
||||
function postIt(url, post, returnLocation) {
|
||||
if (typeof postUrl === 'undefined') {
|
||||
loadPageUsingPost(url, post);
|
||||
} else {
|
||||
postUrl(
|
||||
{
|
||||
url,
|
||||
tabId: returnLocation,
|
||||
type: 'loadPageUsingPost'
|
||||
},
|
||||
post
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function saveDashboard(action) {
|
||||
const btnDialog = {
|
||||
Cancel: {
|
||||
text: monitorMessages.cancel || 'Cancel',
|
||||
id: 'btnCancel',
|
||||
click() {
|
||||
$(this).dialog('close');
|
||||
}
|
||||
},
|
||||
Save: {
|
||||
text: monitorMessages.save || 'Save',
|
||||
id: 'btnSave',
|
||||
click() {
|
||||
saveNewDashboard(action);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if ($('#newdialog').length === 0) {
|
||||
$('body').append(monitorNewForm);
|
||||
}
|
||||
|
||||
$('#newdialog').dialog({
|
||||
title: monitorNewTitle,
|
||||
minHeight: 80,
|
||||
minWidth: 500,
|
||||
buttons: btnDialog,
|
||||
position: { at: 'center top+240px', of: globalThis },
|
||||
open() {
|
||||
$('#name').val($('#dashboard option:selected').text());
|
||||
$('#btnSave').addClass('ui-state-active');
|
||||
$('#name').focus();
|
||||
$('#new_dashboard')
|
||||
.off('submit')
|
||||
.on('submit', (event) => {
|
||||
event.preventDefault();
|
||||
saveNewDashboard('new');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(() => {
|
||||
if (dozoomRefresh) {
|
||||
applyFilter('refresh');
|
||||
}
|
||||
|
||||
const selectmenu = $('#grouping').selectmenu('instance') !== undefined;
|
||||
|
||||
if ($('#view').val() === 'list') {
|
||||
$('#grouping').prop('disabled', true);
|
||||
if (selectmenu) {
|
||||
$('#grouping').selectmenu('disable');
|
||||
}
|
||||
} else {
|
||||
$('#grouping').prop('disabled', false);
|
||||
if (selectmenu) {
|
||||
$('#grouping').selectmenu('enable');
|
||||
}
|
||||
}
|
||||
|
||||
clearTimeout(myTimer);
|
||||
|
||||
$('#go').click((event) => {
|
||||
event.preventDefault();
|
||||
applyFilter('go');
|
||||
});
|
||||
|
||||
$('#clear').click(() => {
|
||||
loadIt('monitor.php?clear=1&header=false');
|
||||
});
|
||||
|
||||
$('#sound').click(() => {
|
||||
if ($('#mute').val() === 'false') {
|
||||
$('#mute').val('true');
|
||||
muteUnmuteAudio(true);
|
||||
applyFilter('ajax_mute_all');
|
||||
} else {
|
||||
$('#mute').val('false');
|
||||
muteUnmuteAudio(false);
|
||||
applyFilter('ajax_unmute_all');
|
||||
}
|
||||
});
|
||||
|
||||
$('#refresh, #view, #rows, #trim, #crit, #grouping, #size, #status, #tree, #site, #template').change(() => {
|
||||
applyFilter('change');
|
||||
});
|
||||
|
||||
$('#dashboard').change(() => {
|
||||
applyFilter('dashboard');
|
||||
});
|
||||
|
||||
$('#save').click(() => {
|
||||
saveFilter();
|
||||
});
|
||||
|
||||
$('#new').click(() => {
|
||||
saveDashboard('new');
|
||||
});
|
||||
|
||||
$('#rename').click(() => {
|
||||
saveDashboard('rename');
|
||||
});
|
||||
|
||||
$('#delete').click(() => {
|
||||
removeDashboard();
|
||||
});
|
||||
|
||||
$('.monitorFilterForm').submit((event) => {
|
||||
event.preventDefault();
|
||||
applyFilter('change');
|
||||
});
|
||||
|
||||
$('.monitor_device_frame').find('i').tooltip({
|
||||
items: '.mon_icon',
|
||||
open(event, ui) {
|
||||
ajaxAnchors();
|
||||
|
||||
if (event.originalEvent === undefined) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
close(event, ui) {
|
||||
ui.tooltip.hover(
|
||||
function() {
|
||||
$(this).stop(true).fadeTo(400, 1);
|
||||
},
|
||||
function() {
|
||||
$(this).fadeOut('400');
|
||||
}
|
||||
);
|
||||
},
|
||||
position: { my: 'left:15 top', at: 'right center' },
|
||||
content(callback) {
|
||||
const id = $(this).attr('id');
|
||||
const size = $('#size').val();
|
||||
$.get(`monitor.php?action=ajax_status&size=${size}&id=${id}`, (data) => {
|
||||
callback(data);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
myTimer = setTimeout(timeStep, 1000);
|
||||
|
||||
$(globalThis).resize(() => {
|
||||
$(document).tooltip('option', 'position', { my: 'left:15 top', at: 'right center' });
|
||||
});
|
||||
|
||||
if ($('#mute').val() === 'true') {
|
||||
muteUnmuteAudio(true);
|
||||
} else {
|
||||
muteUnmuteAudio(false);
|
||||
}
|
||||
|
||||
$('#main').css('margin-right', '15px');
|
||||
});
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
|
||||
+22
-2585
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
+1236
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
+36
-810
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
@@ -25,28 +28,32 @@
|
||||
$dir = __DIR__;
|
||||
chdir($dir);
|
||||
|
||||
include('../../include/cli_check.php');
|
||||
include_once($config['base_path'] . '/lib/reports.php');
|
||||
include_once '../../include/cli_check.php';
|
||||
include_once $config['base_path'] . '/lib/reports.php';
|
||||
|
||||
// let PHP run just as long as it has to
|
||||
ini_set('max_execution_time', '0');
|
||||
|
||||
error_reporting(E_ALL);
|
||||
|
||||
const MONITOR_DATE_TIME_FORMAT = 'Y-m-d H:i:s';
|
||||
const MONITOR_PING_NOTIFICATION_SUBJECT = 'Cacti Monitor Plugin Ping Threshold Notification';
|
||||
const MONITOR_ALERT_PING_LABEL = 'Alert Ping';
|
||||
const MONITOR_CURRENT_PING_LABEL = 'Current Ping';
|
||||
|
||||
// record the start time
|
||||
$poller_start = microtime(true);
|
||||
$start_date = date('Y-m-d H:i:s');
|
||||
$start_date = date(MONITOR_DATE_TIME_FORMAT);
|
||||
|
||||
global $config, $database_default, $purged_r, $purged_n;
|
||||
global $config, $database_default;
|
||||
|
||||
include_once __DIR__ . '/poller_functions.php';
|
||||
|
||||
// process calling arguments
|
||||
$parms = $_SERVER['argv'];
|
||||
array_shift($parms);
|
||||
|
||||
$debug = false;
|
||||
$force = false;
|
||||
$purged_r = 0;
|
||||
$purged_n = 0;
|
||||
$debug = false;
|
||||
|
||||
if (cacti_sizeof($parms)) {
|
||||
foreach ($parms as $parameter) {
|
||||
@@ -61,82 +68,77 @@ if (cacti_sizeof($parms)) {
|
||||
case '--version':
|
||||
case '-V':
|
||||
case '-v':
|
||||
display_version();
|
||||
displayVersion();
|
||||
exit;
|
||||
case '--help':
|
||||
case '-H':
|
||||
case '-h':
|
||||
display_help();
|
||||
displayHelp();
|
||||
exit;
|
||||
case '--force':
|
||||
$force = true;
|
||||
|
||||
break;
|
||||
case '--debug':
|
||||
$debug = true;
|
||||
|
||||
break;
|
||||
default:
|
||||
print 'ERROR: Invalid Parameter ' . $parameter . PHP_EOL . PHP_EOL;
|
||||
display_help();
|
||||
displayHelp();
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
monitor_debug('Monitor Starting Checks');
|
||||
monitorDebug('Monitor Starting Checks');
|
||||
|
||||
[$reboots, $recent_down] = monitor_uptime_checker();
|
||||
[$reboots, $recent_down] = monitorUptimeChecker();
|
||||
|
||||
$warning_criticality = read_config_option('monitor_warn_criticality');
|
||||
$alert_criticality = read_config_option('monitor_alert_criticality');
|
||||
|
||||
$lists = [];
|
||||
$notifications = 0;
|
||||
$global_list = [];
|
||||
$notify_list = [];
|
||||
$last_time = date('Y-m-d H:i:s', time() - read_config_option('monitor_resend_frequency') * 60);
|
||||
$lists = [];
|
||||
$notifications = 0;
|
||||
$global_list = [];
|
||||
$notify_list = [];
|
||||
|
||||
if ($warning_criticality > 0 || $alert_criticality > 0) {
|
||||
monitor_debug('Monitor Notification Enabled for Devices');
|
||||
monitorDebug('Monitor Notification Enabled for Devices');
|
||||
|
||||
// Get hosts that are above threshold. Start with Alert, and then Warning
|
||||
// Get hosts that are above threshold. Start with Alert, and then Warning.
|
||||
if ($alert_criticality) {
|
||||
get_hosts_by_list_type('alert', $alert_criticality, $global_list, $notify_list, $lists);
|
||||
getHostsByListType('alert', $alert_criticality, $global_list, $notify_list, $lists);
|
||||
}
|
||||
|
||||
if ($warning_criticality) {
|
||||
get_hosts_by_list_type('warn', $warning_criticality, $global_list, $notify_list, $lists);
|
||||
getHostsByListType('warn', $warning_criticality, $global_list, $notify_list, $lists);
|
||||
}
|
||||
|
||||
flatten_lists($global_list, $notify_list);
|
||||
flattenLists($global_list, $notify_list);
|
||||
|
||||
monitor_debug('Lists Flattened there are ' . sizeof($global_list) . ' Global Notifications and ' . sizeof($notify_list) . ' Notification List Notifications.');
|
||||
monitorDebug('Lists Flattened there are ' . sizeof($global_list) . ' Global Notifications and ' . sizeof($notify_list) . ' Notification List Notifications.');
|
||||
|
||||
if (strlen(read_config_option('alert_email')) == 0) {
|
||||
monitor_debug('WARNING: No Global List Defined. Please set under Settings -> Thresholds');
|
||||
monitorDebug('WARNING: No Global List Defined. Please set under Settings -> Thresholds');
|
||||
cacti_log('WARNING: No Global Notification List defined. Please set under Settings -> Thresholds', false, 'MONITOR');
|
||||
}
|
||||
|
||||
if (cacti_sizeof($global_list) || sizeof($notify_list)) {
|
||||
// array of email[list|'g'] = true;
|
||||
$notification_emails = get_emails_and_lists($lists);
|
||||
$notification_emails = getEmailsAndLists($lists);
|
||||
|
||||
// Send out emails to each emails address with all notifications in one
|
||||
if (cacti_sizeof($notification_emails)) {
|
||||
foreach ($notification_emails as $email => $lists) {
|
||||
monitor_debug('Processing the email address: ' . $email);
|
||||
process_email($email, $lists, $global_list, $notify_list);
|
||||
monitorDebug('Processing the email address: ' . $email);
|
||||
processEmail($email, $lists, $global_list, $notify_list);
|
||||
|
||||
$notifications++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
monitor_debug('Both Warning and Alert Notification are Disabled.');
|
||||
monitorDebug('Both Warning and Alert Notification are Disabled.');
|
||||
}
|
||||
|
||||
[$purge_n, $purge_r] = purge_event_records();
|
||||
[$purge_n, $purge_r] = purgeEventRecords();
|
||||
|
||||
$poller_end = microtime(true);
|
||||
|
||||
@@ -151,779 +153,3 @@ cacti_log('MONITOR STATS: ' . $stats, false, 'SYSTEM');
|
||||
set_config_option('stats_monitor', $stats);
|
||||
|
||||
exit;
|
||||
|
||||
function monitor_addemails(&$reboot_emails, $alert_emails, $host_id) {
|
||||
if (cacti_sizeof($alert_emails)) {
|
||||
foreach ($alert_emails as $email) {
|
||||
$reboot_emails[trim(strtolower($email))][$host_id] = $host_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function monitor_addnotificationlist(&$reboot_emails, $notify_list, $host_id, $notification_lists) {
|
||||
if ($notify_list > 0) {
|
||||
if (isset($notification_lists[$notify_list])) {
|
||||
$emails = explode(',', $notification_lists[$notify_list]);
|
||||
monitor_addemails($reboot_emails, $emails, $host_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function monitor_uptime_checker() {
|
||||
monitor_debug('Checking for Uptime of Devices');
|
||||
|
||||
$start = date('Y-m-d H:i:s');
|
||||
|
||||
$reboot_emails = [];
|
||||
|
||||
$alert_email = read_config_option('alert_email');
|
||||
|
||||
if ($alert_email != '') {
|
||||
$alert_emails = explode(',', $alert_email);
|
||||
} else {
|
||||
$alert_emails = [];
|
||||
}
|
||||
|
||||
// Remove unneeded device records in associated tables
|
||||
$removed_hosts = db_fetch_assoc('SELECT mu.host_id
|
||||
FROM plugin_monitor_uptime AS mu
|
||||
LEFT JOIN host AS h
|
||||
ON h.id = mu.host_id
|
||||
WHERE h.id IS NULL');
|
||||
|
||||
if (cacti_sizeof($removed_hosts)) {
|
||||
db_execute('DELETE mu
|
||||
FROM plugin_monitor_uptime AS mu
|
||||
LEFT JOIN host AS h
|
||||
ON h.id = mu.host_id
|
||||
WHERE h.id IS NULL');
|
||||
}
|
||||
|
||||
$removed_hosts = db_fetch_assoc('SELECT mu.host_id
|
||||
FROM plugin_monitor_reboot_history AS mu
|
||||
LEFT JOIN host AS h
|
||||
ON h.id = mu.host_id
|
||||
WHERE h.id IS NULL');
|
||||
|
||||
if (cacti_sizeof($removed_hosts)) {
|
||||
db_execute('DELETE mu
|
||||
FROM plugin_monitor_reboot_history AS mu
|
||||
LEFT JOIN host AS h
|
||||
ON h.id = mu.host_id
|
||||
WHERE h.id IS NULL');
|
||||
}
|
||||
|
||||
// Get the rebooted devices
|
||||
$rebooted_hosts = db_fetch_assoc('SELECT h.id, h.description,
|
||||
h.hostname, h.snmp_sysUpTimeInstance, mu.uptime
|
||||
FROM host AS h
|
||||
LEFT JOIN plugin_monitor_uptime AS mu
|
||||
ON h.id = mu.host_id
|
||||
WHERE h.snmp_version > 0
|
||||
AND status IN (2,3)
|
||||
AND h.deleted = ""
|
||||
AND h.monitor = "on"
|
||||
AND (mu.uptime IS NULL OR mu.uptime > h.snmp_sysUpTimeInstance)
|
||||
AND h.snmp_sysUpTimeInstance > 0');
|
||||
|
||||
if (cacti_sizeof($rebooted_hosts)) {
|
||||
$notification_lists = array_rekey(
|
||||
db_fetch_assoc('SELECT id, emails
|
||||
FROM plugin_notification_lists
|
||||
ORDER BY id'),
|
||||
'id', 'emails'
|
||||
);
|
||||
|
||||
$monitor_list = read_config_option('monitor_list');
|
||||
$monitor_thold = read_config_option('monitor_reboot_thold');
|
||||
|
||||
foreach ($rebooted_hosts as $host) {
|
||||
db_execute_prepared('INSERT INTO plugin_monitor_reboot_history
|
||||
(host_id, reboot_time)
|
||||
VALUES (?, ?)',
|
||||
[$host['id'], date('Y-m-d H:i:s', time() - intval($host['snmp_sysUpTimeInstance']))]);
|
||||
|
||||
monitor_addnotificationlist($reboot_emails, $monitor_list, $host['id'], $notification_lists);
|
||||
|
||||
if ($monitor_thold == 'on') {
|
||||
$notify = db_fetch_row_prepared('SELECT thold_send_email, thold_host_email
|
||||
FROM host
|
||||
WHERE id = ?',
|
||||
[$host['id']]);
|
||||
|
||||
if (cacti_sizeof($notify)) {
|
||||
switch($notify['thold_send_email']) {
|
||||
case '0': // Disabled
|
||||
break;
|
||||
case '1': // Global List
|
||||
monitor_addemails($reboot_emails, $alert_emails, $host['id']);
|
||||
|
||||
break;
|
||||
case '2': // Nofitication List
|
||||
monitor_addnotificationlist($reboot_emails, $notify['thold_host_email'],
|
||||
$host['id'], $notification_lists);
|
||||
|
||||
break;
|
||||
case '3': // Both Global and Nofication list
|
||||
monitor_addemails($reboot_emails, $alert_emails, $host['id']);
|
||||
monitor_addnotificationlist($reboot_emails, $notify['thold_host_email'],
|
||||
$host['id'], $notification_lists);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$monitor_send_one_email = read_config_option('monitor_send_one_email');
|
||||
$to_email = '';
|
||||
|
||||
if (cacti_sizeof($reboot_emails)) {
|
||||
foreach ($reboot_emails as $email => $hosts) {
|
||||
if ($email != '') {
|
||||
$to_email .= ($to_email != '' ? ',' : '') . $email;
|
||||
|
||||
if ($monitor_send_one_email !== 'on') {
|
||||
monitor_debug('Processing the Email address: ' . $email);
|
||||
process_reboot_email($email, $hosts);
|
||||
}
|
||||
} else {
|
||||
monitor_debug('Unable to process reboot notification due to empty Email address.');
|
||||
}
|
||||
}
|
||||
|
||||
if ($monitor_send_one_email == 'on') {
|
||||
monitor_debug('Processing the Email address: ' . $to_email);
|
||||
process_reboot_email($to_email, $hosts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Freshen the uptimes
|
||||
db_execute('REPLACE INTO plugin_monitor_uptime
|
||||
(host_id, uptime)
|
||||
SELECT id, snmp_sysUpTimeInstance
|
||||
FROM host
|
||||
WHERE snmp_version > 0
|
||||
AND status IN(2,3)
|
||||
AND deleted = ""
|
||||
AND monitor = "on"
|
||||
AND snmp_sysUpTimeInstance > 0');
|
||||
|
||||
// Log Recently Down
|
||||
db_execute('INSERT IGNORE INTO plugin_monitor_notify_history
|
||||
(host_id, notify_type, notification_time, notes)
|
||||
SELECT h.id, "3" AS notify_type, status_fail_date AS notification_time, status_last_error AS notes
|
||||
FROM host AS h
|
||||
WHERE status = 1
|
||||
AND deleted = ""
|
||||
AND monitor = "on"
|
||||
AND status_event_count = 1');
|
||||
|
||||
$recent = db_affected_rows();
|
||||
|
||||
return [cacti_sizeof($rebooted_hosts), $recent];
|
||||
}
|
||||
|
||||
function process_reboot_email($email, $hosts) {
|
||||
monitor_debug("Reboot Processing for $email starting");
|
||||
|
||||
$body_txt = '';
|
||||
|
||||
$body = '<table class="report_table">' . PHP_EOL;
|
||||
$body .= '<tr class="header_row">' . PHP_EOL;
|
||||
|
||||
$body .=
|
||||
'<th class="left">' . __('Description', 'monitor') . '</th>' .
|
||||
'<th class="left">' . __('Hostname', 'monitor') . '</th>' . PHP_EOL;
|
||||
|
||||
$body .= '</tr>' . PHP_EOL;
|
||||
|
||||
foreach ($hosts as $host) {
|
||||
$host = db_fetch_row_prepared('SELECT description, hostname
|
||||
FROM host
|
||||
WHERE id = ?',
|
||||
[$host]);
|
||||
|
||||
if (cacti_sizeof($host)) {
|
||||
$body .= '<tr>' .
|
||||
'<td class="left">' . $host['description'] . '</td>' .
|
||||
'<td class="left">' . $host['hostname'] . '</td>' .
|
||||
'</tr>' . PHP_EOL;
|
||||
|
||||
$body_txt .=
|
||||
__('Description: ', 'monitor') . $host['description'] . PHP_EOL .
|
||||
__('Hostname: ', 'monitor') . $host['hostname'] . PHP_EOL . PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
$body .= '</table>' . PHP_EOL;
|
||||
|
||||
$subject = read_config_option('monitor_subject');
|
||||
$monitor_send_one_email = read_config_option('monitor_send_one_email');
|
||||
|
||||
if ($monitor_send_one_email == 'on') {
|
||||
$subject .= ' ' . $host['description'] . ' (' . $host['hostname'] . ')';
|
||||
} else {
|
||||
if (cacti_sizeof($hosts) == 1) {
|
||||
$subject .= ' 1 device - ' . $host['description'] . ' (' . $host['hostname'] . ')';
|
||||
} else {
|
||||
$subject .= ' ' . cacti_sizeof($hosts) . ' devices';
|
||||
}
|
||||
}
|
||||
|
||||
$output = read_config_option('monitor_body');
|
||||
$output = str_replace('<DETAILS>', $body, $output) . PHP_EOL;
|
||||
|
||||
if (strpos($output, '<DETAILS>') !== false) {
|
||||
$toutput = str_replace('<DETAILS>', $body_txt, $output) . PHP_EOL;
|
||||
} else {
|
||||
$toutput = $body_txt;
|
||||
}
|
||||
|
||||
if (read_config_option('monitor_reboot_notify') == 'on') {
|
||||
$report_tag = '';
|
||||
$theme = 'modern';
|
||||
|
||||
monitor_debug('Loading Format File');
|
||||
|
||||
$format_ok = reports_load_format_file(read_config_option('monitor_format_file'), $output, $report_tag, $theme);
|
||||
|
||||
monitor_debug('Format File Loaded, Format is ' . ($format_ok ? 'Ok' : 'Not Ok') . ', Report Tag is ' . $report_tag);
|
||||
|
||||
if ($format_ok) {
|
||||
if ($report_tag) {
|
||||
$output = str_replace('<REPORT>', $body, $output);
|
||||
} else {
|
||||
$output = $output . PHP_EOL . $body;
|
||||
}
|
||||
} else {
|
||||
$output = $body;
|
||||
}
|
||||
|
||||
monitor_debug('HTML Processed');
|
||||
|
||||
if (defined('CACTI_VERSION')) {
|
||||
$version = CACTI_VERSION;
|
||||
} else {
|
||||
$version = get_cacti_version();
|
||||
}
|
||||
|
||||
$headers['User-Agent'] = 'Cacti-Monitor-v' . $version;
|
||||
|
||||
$status = 'Reboot Notifications';
|
||||
|
||||
process_send_email($email, $subject, $output, $toutput, $headers, $status);
|
||||
}
|
||||
}
|
||||
|
||||
function process_email($email, $lists, $global_list, $notify_list) {
|
||||
global $config;
|
||||
|
||||
monitor_debug('Into Processing');
|
||||
|
||||
$alert_hosts = [];
|
||||
$warn_hosts = [];
|
||||
|
||||
$criticalities = [
|
||||
0 => __('Disabled', 'monnitor'),
|
||||
1 => __('Low', 'monnitor'),
|
||||
2 => __('Medium', 'monnitor'),
|
||||
3 => __('High', 'monnitor'),
|
||||
4 => __('Mission Critical', 'monnitor')
|
||||
];
|
||||
|
||||
foreach ($lists as $list) {
|
||||
switch($list) {
|
||||
case 'global':
|
||||
$hosts = [];
|
||||
|
||||
if (isset($global_list['alert'])) {
|
||||
$alert_hosts += explode(',', $global_list['alert']);
|
||||
}
|
||||
|
||||
if (isset($global_list['warn'])) {
|
||||
$warn_hosts += explode(',', $global_list['warn']);
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
if (isset($notify_list[$list]['alert'])) {
|
||||
$alert_hosts = explode(',', $notify_list[$list]['alert']);
|
||||
}
|
||||
|
||||
if (isset($notify_list[$list]['warn'])) {
|
||||
$warn_hosts = explode(',', $notify_list[$list]['warn']);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
monitor_debug('Lists Processed');
|
||||
|
||||
if (cacti_sizeof($alert_hosts)) {
|
||||
$alert_hosts = array_unique($alert_hosts, SORT_NUMERIC);
|
||||
|
||||
log_messages('alert', $alert_hosts);
|
||||
}
|
||||
|
||||
if (cacti_sizeof($warn_hosts)) {
|
||||
$warn_hosts = array_unique($warn_hosts, SORT_NUMERIC);
|
||||
|
||||
log_messages('warn', $alert_hosts);
|
||||
}
|
||||
|
||||
monitor_debug('Found ' . sizeof($alert_hosts) . ' Alert Hosts, and ' . sizeof($warn_hosts) . ' Warn Hosts');
|
||||
|
||||
if (cacti_sizeof($alert_hosts) || sizeof($warn_hosts)) {
|
||||
monitor_debug('Formatting Email');
|
||||
|
||||
$freq = read_config_option('monitor_resend_frequency');
|
||||
$subject = __('Cacti Monitor Plugin Ping Threshold Notification', 'monitor');
|
||||
|
||||
$body = '<h1>' . __('Cacti Monitor Plugin Ping Threshold Notification', 'monitor') . '</h1>' . PHP_EOL;
|
||||
$body_txt = __('Cacti Monitor Plugin Ping Threshold Notification', 'monitor') . PHP_EOL;
|
||||
|
||||
$body .= '<p>' . __('The following report will identify Devices that have eclipsed their ping latency thresholds. You are receiving this report since you are subscribed to a Device associated with the Cacti system located at the following URL below.') . '</p>' . PHP_EOL;
|
||||
|
||||
$body_txt .= __('The following report will identify Devices that have eclipsed their ping latency thresholds. You are receiving this report since you are subscribed to a Device associated with the Cacti system located at the following URL below.') . PHP_EOL;
|
||||
|
||||
$body .= '<h2><a href="' . read_config_option('base_url') . '">Cacti Monitoring Site</a></h2>' . PHP_EOL;
|
||||
|
||||
$body_txt .= __('Cacti Monitoring Site', 'monitor') . PHP_EOL;
|
||||
|
||||
if ($freq > 0) {
|
||||
$body .= '<p>' . __('You will receive notifications every %d minutes if the Device is above its threshold.', $freq, 'monitor') . '</p>' . PHP_EOL;
|
||||
|
||||
$body_txt .= __('You will receive notifications every %d minutes if the Device is above its threshold.', $freq, 'monitor') . PHP_EOL;
|
||||
} else {
|
||||
$body .= '<p>' . __('You will receive notifications every time the Device is above its threshold.', 'monitor') . '</p>' . PHP_EOL;
|
||||
|
||||
$body_txt .= __('You will receive notifications every time the Device is above its threshold.', 'monitor') . PHP_EOL;
|
||||
}
|
||||
|
||||
if (cacti_sizeof($alert_hosts)) {
|
||||
$body .= '<p>' . __('The following Devices have breached their Alert Notification Threshold.', 'monitor') . '</p>' . PHP_EOL;
|
||||
|
||||
$body_txt .= __('The following Devices have breached their Alert Notification Threshold.', 'monitor') . PHP_EOL;
|
||||
|
||||
$body .= '<table class="report_table">' . PHP_EOL;
|
||||
$body .= '<tr class="header_row">' . PHP_EOL;
|
||||
|
||||
$body .=
|
||||
'<th class="left">' . __('Hostname', 'monitor') . '</th>' .
|
||||
'<th class="left">' . __('Criticality', 'monitor') . '</th>' .
|
||||
'<th class="right">' . __('Alert Ping', 'monitor') . '</th>' .
|
||||
'<th class="right">' . __('Current Ping', 'monitor') . '</th>' . PHP_EOL;
|
||||
|
||||
$body_txt .=
|
||||
__('Hostname', 'monitor') . "\t" .
|
||||
__('Criticality', 'monitor') . "\t" .
|
||||
__('Alert Ping', 'monitor') . "\t" .
|
||||
__('Current Ping', 'monitor') . PHP_EOL;
|
||||
|
||||
$body .= '</tr>' . PHP_EOL;
|
||||
|
||||
$hosts = db_fetch_assoc('SELECT *
|
||||
FROM host
|
||||
WHERE id IN(' . implode(',', $alert_hosts) . ')
|
||||
AND deleted = ""');
|
||||
|
||||
if (cacti_sizeof($hosts)) {
|
||||
foreach ($hosts as $host) {
|
||||
$body .= '<tr>' . PHP_EOL;
|
||||
$body .= '<td class="left"><a class="hyperLink" href="' . htmlspecialchars($config['url_path'] . 'host.php?action=edit&id=' . $host['id']) . '">' . $host['description'] . '</a></td>' . PHP_EOL;
|
||||
|
||||
$body .= '<td class="left">' . $criticalities[$host['monitor_criticality']] . '</td>' . PHP_EOL;
|
||||
$body .= '<td class="right">' . number_format_i18n($host['monitor_alert'],2) . ' ms</td>' . PHP_EOL;
|
||||
$body .= '<td class="right">' . number_format_i18n($host['cur_time'],2) . ' ms</td>' . PHP_EOL;
|
||||
|
||||
$body_txt .=
|
||||
$host['description'] . "\t" .
|
||||
$criticalities[$host['monitor_criticality']] . "\t" .
|
||||
number_format_i18n($host['monitor_alert'],2) . " ms\t" .
|
||||
number_format_i18n($host['cur_time'],2) . ' ms' . PHP_EOL;
|
||||
|
||||
$body .= '</tr>' . PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
$body .= '</table>' . PHP_EOL;
|
||||
}
|
||||
|
||||
if (cacti_sizeof($warn_hosts)) {
|
||||
$body .= '<p>' . __('The following Devices have breached their Warning Notification Threshold.', 'monitor') . '</p>' . PHP_EOL;
|
||||
|
||||
$body_txt .= __('The following Devices have breached their Warning Notification Threshold.', 'monitor') . PHP_EOL;
|
||||
|
||||
$body .= '<table class="report_table">' . PHP_EOL;
|
||||
$body .= '<tr class="header_row">' . PHP_EOL;
|
||||
|
||||
$body .=
|
||||
'<th class="left">' . __('Hostname', 'monitor') . '</th>' .
|
||||
'<th class="left">' . __('Criticality', 'monitor') . '</th>' .
|
||||
'<th class="right">' . __('Alert Ping', 'monitor') . '</th>' .
|
||||
'<th class="right">' . __('Current Ping', 'monitor') . '</th>' . PHP_EOL;
|
||||
|
||||
$body_txt .=
|
||||
__('Hostname', 'monitor') . "\t" .
|
||||
__('Criticality', 'monitor') . "\t" .
|
||||
__('Alert Ping', 'monitor') . "\t" .
|
||||
__('Current Ping', 'monitor') . PHP_EOL;
|
||||
|
||||
$body .= '</tr>' . PHP_EOL;
|
||||
|
||||
$hosts = db_fetch_assoc('SELECT *
|
||||
FROM host
|
||||
WHERE id IN(' . implode(',', $warn_hosts) . ')
|
||||
AND deleted = ""');
|
||||
|
||||
if (cacti_sizeof($hosts)) {
|
||||
foreach ($hosts as $host) {
|
||||
$body .= '<tr>' . PHP_EOL;
|
||||
$body .= '<td class="left"><a class="hyperLink" href="' . htmlspecialchars($config['url_path'] . 'host.php?action=edit&id=' . $host['id']) . '">' . $host['description'] . '</a></td>' . PHP_EOL;
|
||||
|
||||
$body .= '<td class="left">' . $criticalities[$host['monitor_criticality']] . '</td>' . PHP_EOL;
|
||||
$body .= '<td class="right">' . number_format_i18n($host['monitor_warn'],2) . ' ms</td>' . PHP_EOL;
|
||||
$body .= '<td class="right">' . number_format_i18n($host['cur_time'],2) . ' ms</td>' . PHP_EOL;
|
||||
|
||||
$body_txt .=
|
||||
$host['description'] . "\t" .
|
||||
$criticalities[$host['monitor_criticality']] . "\t" .
|
||||
number_format_i18n($host['monitor_alert'],2) . " ms\t" .
|
||||
number_format_i18n($host['cur_time'],2) . ' ms' . PHP_EOL;
|
||||
|
||||
$body .= '</tr>' . PHP_EOL;
|
||||
}
|
||||
}
|
||||
$body .= '</table>' . PHP_EOL;
|
||||
}
|
||||
|
||||
$output = '';
|
||||
$toutput = $body_txt;
|
||||
$report_tag = '';
|
||||
$theme = 'modern';
|
||||
|
||||
monitor_debug('Loading Format File');
|
||||
|
||||
$format_ok = reports_load_format_file(read_config_option('monitor_format_file'), $output, $report_tag, $theme);
|
||||
|
||||
monitor_debug('Format File Loaded, Format is ' . ($format_ok ? 'Ok' : 'Not Ok') . ', Report Tag is ' . $report_tag);
|
||||
|
||||
if ($format_ok) {
|
||||
if ($report_tag) {
|
||||
$output = str_replace('<REPORT>', $body, $output);
|
||||
} else {
|
||||
$output = $output . PHP_EOL . $body;
|
||||
}
|
||||
} else {
|
||||
$output = $body;
|
||||
}
|
||||
|
||||
monitor_debug('HTML Processed');
|
||||
|
||||
if (defined('CACTI_VERSION')) {
|
||||
$version = CACTI_VERSION;
|
||||
} else {
|
||||
$version = get_cacti_version();
|
||||
}
|
||||
|
||||
$headers['User-Agent'] = 'Cacti-Monitor-v' . $version;
|
||||
|
||||
$status = (cacti_sizeof($alert_hosts) ? sizeof($alert_hosts) . ' Alert Notifications' : '') .
|
||||
(cacti_sizeof($warn_hosts) ? (cacti_sizeof($alert_hosts) ? ', and ' : '') .
|
||||
sizeof($warn_hosts) . ' Warning Notifications' : '');
|
||||
|
||||
process_send_email($email, $subject, $output, $toutput, $headers, $status);
|
||||
}
|
||||
}
|
||||
|
||||
function process_send_email($email, $subject, $output, $toutput, $headers, $status) {
|
||||
$from_email = read_config_option('monitor_fromemail');
|
||||
|
||||
if ($from_email == '') {
|
||||
$from_email = read_config_option('settings_from_email');
|
||||
|
||||
if ($from_email == '') {
|
||||
$from_email = 'Cacti@cacti.net';
|
||||
}
|
||||
}
|
||||
|
||||
$from_name = read_config_option('monitor_fromname');
|
||||
|
||||
if ($from_name != '') {
|
||||
$from_name = read_config_option('settings_from_name');
|
||||
|
||||
if ($from_name == '') {
|
||||
$from_name = 'Cacti Reporting';
|
||||
}
|
||||
}
|
||||
|
||||
$html = true;
|
||||
|
||||
if (read_config_option('thold_send_text_only') == 'on') {
|
||||
$output = monitor_text($toutput);
|
||||
$html = false;
|
||||
}
|
||||
|
||||
monitor_debug("Sending Email to '$email' for $status");
|
||||
|
||||
$error = mailer(
|
||||
[$from_email, $from_name],
|
||||
$email,
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
$subject,
|
||||
$output,
|
||||
monitor_text($toutput),
|
||||
null,
|
||||
$headers,
|
||||
$html
|
||||
);
|
||||
|
||||
monitor_debug("The return from the mailer was '$error'");
|
||||
|
||||
if (strlen($error)) {
|
||||
cacti_log("WARNING: Monitor had problems sending to '$email' for $status. The error was '$error'", false, 'MONITOR');
|
||||
} else {
|
||||
cacti_log("NOTICE: Email Notification Sent to '$email' for $status.", false, 'MONITOR');
|
||||
}
|
||||
}
|
||||
|
||||
function monitor_text($output) {
|
||||
$output = explode(PHP_EOL, $output);
|
||||
|
||||
$new_output = '';
|
||||
|
||||
if (cacti_sizeof($output)) {
|
||||
foreach ($output as $line) {
|
||||
$line = str_replace('<br>', PHP_EOL, $line);
|
||||
$line = str_replace('<br />', PHP_EOL, $line);
|
||||
$line = trim(strip_tags($line));
|
||||
$new_output .= $line . PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
return $new_output;
|
||||
}
|
||||
|
||||
function log_messages($type, $alert_hosts) {
|
||||
global $start_date;
|
||||
|
||||
static $processed = [];
|
||||
|
||||
if ($type == 'warn') {
|
||||
$type = '0';
|
||||
$column = 'monitor_warn';
|
||||
} elseif ($type == 'alert') {
|
||||
$type = '1';
|
||||
$column = 'monitor_alert';
|
||||
}
|
||||
|
||||
foreach ($alert_hosts as $id) {
|
||||
if (!isset($processed[$id])) {
|
||||
db_execute_prepared("INSERT INTO plugin_monitor_notify_history
|
||||
(host_id, notify_type, ping_time, ping_threshold, notification_time)
|
||||
SELECT id, '$type' AS notify_type, cur_time, $column, '$start_date' AS notification_time
|
||||
FROM host
|
||||
WHERE deleted = ''
|
||||
AND monitor = 'on'
|
||||
AND id = ?",
|
||||
[$id]);
|
||||
}
|
||||
|
||||
$processed[$id] = true;
|
||||
}
|
||||
}
|
||||
|
||||
function get_hosts_by_list_type($type, $criticality, &$global_list, &$notify_list, &$lists) {
|
||||
global $force;
|
||||
|
||||
$last_time = date('Y-m-d H:i:s', time() - read_config_option('monitor_resend_frequency') * 60);
|
||||
|
||||
$hosts = db_fetch_cell_prepared("SELECT COUNT(*)
|
||||
FROM host
|
||||
WHERE status = 3
|
||||
AND deleted = ''
|
||||
AND monitor = 'on'
|
||||
AND thold_send_email > 0
|
||||
AND monitor_criticality >= ?
|
||||
AND cur_time > monitor_$type",
|
||||
[$criticality]);
|
||||
|
||||
if ($type == 'warn') {
|
||||
$htype = 1;
|
||||
} else {
|
||||
$htype = 0;
|
||||
}
|
||||
|
||||
if ($hosts > 0) {
|
||||
$groups = db_fetch_assoc_prepared("SELECT
|
||||
thold_send_email, thold_host_email, GROUP_CONCAT(host.id) AS id
|
||||
FROM host
|
||||
LEFT JOIN (
|
||||
SELECT host_id, MAX(notification_time) AS notification_time
|
||||
FROM plugin_monitor_notify_history
|
||||
WHERE notify_type = ?
|
||||
GROUP BY host_id
|
||||
) AS nh
|
||||
ON host.id=nh.host_id
|
||||
WHERE status = 3
|
||||
AND deleted = ''
|
||||
AND monitor = 'on'
|
||||
AND thold_send_email > 0
|
||||
AND monitor_criticality >= ?
|
||||
AND cur_time > monitor_$type " . ($type == 'warn' ? ' AND cur_time < monitor_alert' : '') . '
|
||||
AND (notification_time < ? OR notification_time IS NULL)
|
||||
AND host.total_polls > 1
|
||||
GROUP BY thold_host_email, thold_send_email
|
||||
ORDER BY thold_host_email, thold_send_email',
|
||||
[$htype, $criticality, $last_time]);
|
||||
|
||||
if (cacti_sizeof($groups)) {
|
||||
foreach ($groups as $entry) {
|
||||
switch($entry['thold_send_email']) {
|
||||
case '1': // Global List
|
||||
$global_list[$type][] = $entry;
|
||||
|
||||
break;
|
||||
case '2': // Notification List
|
||||
if ($entry['thold_host_email'] > 0) {
|
||||
$notify_list[$type][$entry['thold_host_email']][] = $entry;
|
||||
$lists[$entry['thold_host_email']] = $entry['thold_host_email'];
|
||||
}
|
||||
|
||||
break;
|
||||
case '3': // Both Notification and Global
|
||||
$global_list[$type][] = $entry;
|
||||
|
||||
if ($entry['thold_host_email'] > 0) {
|
||||
$notify_list[$type][$entry['thold_host_email']][] = $entry;
|
||||
$lists[$entry['thold_host_email']] = $entry['thold_host_email'];
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function flatten_lists(&$global_list, &$notify_list) {
|
||||
if (cacti_sizeof($global_list)) {
|
||||
foreach ($global_list as $severity => $list) {
|
||||
foreach ($list as $item) {
|
||||
$new_global[$severity] = (isset($new_global[$severity]) ? $new_global[$severity] . ',' : '') . $item['id'];
|
||||
}
|
||||
}
|
||||
$global_list = $new_global;
|
||||
}
|
||||
|
||||
if (cacti_sizeof($notify_list)) {
|
||||
foreach ($notify_list as $severity => $lists) {
|
||||
foreach ($lists as $id => $list) {
|
||||
foreach ($list as $item) {
|
||||
$new_list[$severity][$id] = (isset($new_list[$severity][$id]) ? $new_list[$severity][$id] . ',' : '') . $item['id'];
|
||||
}
|
||||
}
|
||||
}
|
||||
$notify_list = $new_list;
|
||||
}
|
||||
}
|
||||
|
||||
function get_emails_and_lists($lists) {
|
||||
$notification_emails = [];
|
||||
|
||||
$alert_email = read_config_option('alert_email');
|
||||
|
||||
if ($alert_email != '') {
|
||||
$global_emails = explode(',', $alert_email);
|
||||
} else {
|
||||
$global_emails = [];
|
||||
}
|
||||
|
||||
if (cacti_sizeof($global_emails)) {
|
||||
foreach ($global_emails as $index => $user) {
|
||||
if (trim($user) != '') {
|
||||
$notification_emails[trim($user)]['global'] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cacti_sizeof($lists)) {
|
||||
$list_emails = db_fetch_assoc('SELECT id, emails
|
||||
FROM plugin_notification_lists
|
||||
WHERE id IN (' . implode(',', $lists) . ')');
|
||||
|
||||
if (cacti_sizeof($list_emails)) {
|
||||
foreach ($list_emails as $email) {
|
||||
$emails = explode(',', $email['emails']);
|
||||
|
||||
foreach ($emails as $user) {
|
||||
if (trim($user) != '') {
|
||||
$notification_emails[trim($user)][$email['id']] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $notification_emails;
|
||||
}
|
||||
|
||||
function purge_event_records() {
|
||||
// Purge old records
|
||||
$days = read_config_option('monitor_log_storage');
|
||||
|
||||
if (empty($days)) {
|
||||
$days = 120;
|
||||
}
|
||||
|
||||
db_execute_prepared('DELETE FROM plugin_monitor_notify_history
|
||||
WHERE notification_time < FROM_UNIXTIME(UNIX_TIMESTAMP() - (? * 86400))',
|
||||
[$days]);
|
||||
|
||||
$purge_n = db_affected_rows();
|
||||
|
||||
db_execute_prepared('DELETE FROM plugin_monitor_reboot_history
|
||||
WHERE log_time < FROM_UNIXTIME(UNIX_TIMESTAMP() - (? * 86400))',
|
||||
[$days]);
|
||||
|
||||
$purge_r = db_affected_rows();
|
||||
|
||||
return [$purge_n, $purge_r];
|
||||
}
|
||||
|
||||
function monitor_debug($message) {
|
||||
global $debug;
|
||||
|
||||
if ($debug) {
|
||||
print trim($message) . PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
function display_version() {
|
||||
global $config;
|
||||
|
||||
if (!function_exists('plugin_monitor_version')) {
|
||||
include_once($config['base_path'] . '/plugins/monitor/setup.php');
|
||||
}
|
||||
|
||||
$info = plugin_monitor_version();
|
||||
print 'Cacti Monitor Poller, Version ' . $info['version'] . ', ' . COPYRIGHT_YEARS . PHP_EOL;
|
||||
}
|
||||
|
||||
/*
|
||||
* display_help
|
||||
* displays the usage of the function
|
||||
*/
|
||||
function display_help() {
|
||||
display_version();
|
||||
|
||||
print PHP_EOL;
|
||||
print 'usage: poller_monitor.php [--force] [--debug]' . PHP_EOL . PHP_EOL;
|
||||
print ' --force - force execution, e.g. for testing' . PHP_EOL;
|
||||
print ' --debug - debug execution, e.g. for testing' . PHP_EOL . PHP_EOL;
|
||||
}
|
||||
@@ -215,7 +215,7 @@ function monitor_check_upgrade() {
|
||||
db_execute('ALTER TABLE plugin_monitor_uptime
|
||||
MODIFY COLUMN uptime BIGINT unsigned NOT NULL default "0"');
|
||||
|
||||
api_plugin_db_add_column('monitor', 'host', ['name' => 'monitor_icon', 'type' => 'varchar(30)', 'NULL' => false, 'default' => '', 'after' => 'monitor_alert']);
|
||||
api_plugin_db_add_column('monitor', 'host', ['name' => 'monitor_icon', 'type' => 'varchar(30)', 'NULL' => false, 'default' => '']);
|
||||
|
||||
if (function_exists('api_plugin_upgrade_register')) {
|
||||
api_plugin_upgrade_register('monitor');
|
||||
@@ -1091,12 +1091,27 @@ function monitor_setup_table() {
|
||||
COMMENT='Stores predefined dashboard information for a user or users'");
|
||||
}
|
||||
|
||||
api_plugin_db_add_column('monitor', 'host', ['name' => 'monitor', 'type' => 'char(3)', 'NULL' => true, 'default' => 'on', 'after' => 'disabled']);
|
||||
api_plugin_db_add_column('monitor', 'host', ['name' => 'monitor_text', 'type' => 'varchar(1024)', 'default' => '', 'NULL' => false, 'after' => 'monitor']);
|
||||
api_plugin_db_add_column('monitor', 'host', ['name' => 'monitor_criticality', 'type' => 'tinyint', 'unsigned' => true, 'NULL' => false, 'default' => '0', 'after' => 'monitor_text']);
|
||||
api_plugin_db_add_column('monitor', 'host', ['name' => 'monitor_warn', 'type' => 'double', 'NULL' => false, 'default' => '0', 'after' => 'monitor_criticality']);
|
||||
api_plugin_db_add_column('monitor', 'host', ['name' => 'monitor_alert', 'type' => 'double', 'NULL' => false, 'default' => '0', 'after' => 'monitor_warn']);
|
||||
api_plugin_db_add_column('monitor', 'host', ['name' => 'monitor_icon', 'type' => 'varchar(30)', 'NULL' => false, 'default' => '', 'after' => 'monitor_alert']);
|
||||
if (db_table_exists('host')) {
|
||||
$row_format = db_fetch_cell("SELECT ROW_FORMAT
|
||||
FROM information_schema.tables
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME = 'host'");
|
||||
|
||||
if (strtoupper((string) $row_format) !== 'DYNAMIC') {
|
||||
db_execute('ALTER TABLE host ROW_FORMAT=DYNAMIC');
|
||||
}
|
||||
}
|
||||
|
||||
db_execute('SET SESSION innodb_strict_mode=0');
|
||||
|
||||
api_plugin_db_add_column('monitor', 'host', ['name' => 'monitor', 'type' => 'char(3)', 'NULL' => true, 'default' => 'on']);
|
||||
api_plugin_db_add_column('monitor', 'host', ['name' => 'monitor_text', 'type' => 'text', 'NULL' => false]);
|
||||
api_plugin_db_add_column('monitor', 'host', ['name' => 'monitor_criticality', 'type' => 'tinyint', 'unsigned' => true, 'NULL' => false, 'default' => '0']);
|
||||
api_plugin_db_add_column('monitor', 'host', ['name' => 'monitor_warn', 'type' => 'double', 'NULL' => false, 'default' => '0']);
|
||||
api_plugin_db_add_column('monitor', 'host', ['name' => 'monitor_alert', 'type' => 'double', 'NULL' => false, 'default' => '0']);
|
||||
api_plugin_db_add_column('monitor', 'host', ['name' => 'monitor_icon', 'type' => 'varchar(30)', 'NULL' => false, 'default' => '']);
|
||||
|
||||
db_execute('SET SESSION innodb_strict_mode=1');
|
||||
}
|
||||
|
||||
function monitor_poller_bottom() {
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
sonar.projectKey=plugin_monitor
|
||||
sonar.sources=.
|
||||
sonar.exclusions=vendor/**
|
||||
|
||||
# php:S4833 - "Use namespaces instead of include/require"
|
||||
# This is a Cacti plugin with a required procedural architecture.
|
||||
# Namespaces cannot be used; include_once is the correct and only mechanism.
|
||||
sonar.issue.ignore.multicriteria=e1
|
||||
sonar.issue.ignore.multicriteria.e1.ruleKey=php:S4833
|
||||
sonar.issue.ignore.multicriteria.e1.resourceKey=**/*.php
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
|
||||
Reference in new issue
Block a user