_check_cpu_usage took a single 1-second psutil sample per run, so a momentary
spike raised a CPU ticket -- and because the ticket API reopens a closed ticket
on a matching alert, the same CPU ticket flapped open/closed on every hourly run.
Ticketing is now gated on the 15-minute load average normalized per core (a true
"sustained" signal): a transient spike barely moves the 15-min load, so it no
longer raises or reopens a ticket. The instantaneous percentage is still reported
(dry-run summary + description) and the measured sustained load is shown in the
ticket description; the title stays value-free so it doesn't churn each run. Falls
back to the instantaneous sample only if os.getloadavg() is unavailable.
Adds 5 regression tests.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The LXC storage check runs in every mode, but its results were never
printed in the --dry-run summary, so a --dry-run appeared to skip LXC
storage entirely. Add an "LXC Storage:" section to the summary
(per-container usage %, a warning flag over the LXC_WARNING threshold, and
the issue count) via a small, testable helper `_format_lxc_dry_run()`.
Adds 4 regression tests.
Closes#23
Ref: #23
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two monitoring-logic fixes so hwmonDaemon stops raising spurious hardware
tickets on a Ceph-backed cluster with PBS backups:
- _check_system_drive_indicators: count dmesg Buffer I/O / block errors
per-line and skip non-physical / network-backed devices (Ceph RBD, dm-,
loop). RBD Buffer I/O errors are storage-connectivity events (e.g. a Ceph
mon-session blip), not local drive faults, so they must not raise a
CRITICAL drive alert. Consistent with the existing _is_physical_disk
exclusion. (Fired a false "CRITICAL: Buffer I/O errors (75 occurrences)"
ticket where all 75 were on rbd devices.)
- _get_attribute_thresholds: drop the Power_On_Hours warning/critical
threshold. Drive age alone is not a failure; with 2-3x Ceph redundancy
and PBS backups we run drives to hard-failure rather than replace on age.
The value is still recorded (history/description/new-drive logic) but no
longer generates a ticket. Real failure-predictors (reallocated/pending/
uncorrectable/CRC, self-test, trends) are unchanged.
Adds 7 regression tests (TestSystemDriveIndicators, TestAttributeThresholds).
All 98 tests pass; flake8 clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add 42 new tests covering _get_manufacturer_profile (Seagate/WD/Samsung/Toshiba/
OOS/Ridata/unknown), _should_monitor_attribute, _get_attribute_thresholds,
_get_issue_type, _get_impact_level, and _categorize_issue.
Toshiba MG08 prefix matching and the raised High_Fly_Writes/Command_Timeout
thresholds introduced in the previous commit are now covered by tests.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove unused MagicMock import (F401)
- Move sys.path.insert above third-party imports and add noqa: E402
to the two imports that must follow it (E402)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- lint.yml: add notify-failure Matrix alert job
- test.yml: new workflow running pytest with pytest-cov for coverage
- .coveragerc: omit tests and site-packages from coverage
- .gitignore: ignore __pycache__ and .pyc files
- tests/test_hwmon.py: 49 unit tests covering SystemHealthMonitor
(temperature parsing, service monitoring, disk usage, metric collection,
dry run behaviour); uses unittest.mock to isolate from env/filesystem
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>