Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
# ChangeLog

--- develop ---

--- 1.4.0 ---

* feature: Add support for monitoring UPSes through Network UPS Tools (NUT) as a third collector type, "NUT Based". The poller talks to `upsd` (TCP 3493 by default) over a native PHP socket implementation of the NUT protocol, so no `upsc` or other CLI tool is needed. Optional username/password authentication and STARTTLS (with certificate verification) are supported, and one NUT server can serve several UPSes through the new NUT UPS Name setting. NUT status flags are translated to the existing apcupsd vocabulary (OL to ONLINE, OB to ONBATT, and so on) so the dashboards, fleet totals and alerts keep working unchanged
* issue: Widen the status, model, serial number, firmware, driver and name columns of `apcupsd_ups_stats` so multi-flag NUT statuses and longer NUT strings are not truncated
* feature: Let NUT STARTTLS work with self-signed certificates: a per-UPS CA / Certificate File to verify the server against (certificate and host name are still checked), or an Allow Self-Signed Certificate option that encrypts without verifying the server
* feature: Add a per-UPS Timeout (seconds) setting, 5 by default and limited to 1-120, for `apcupsd` and NUT UPS'. NUT connects and conversations are now bounded by twice the timeout in total, and `apcaccess` is run through Cacti's `exec_with_timeout()` so a hung `apcaccess` can no longer stall the poller; a timed out `apcaccess` now records an error on the UPS
* feature: Make the UPSes table on the Fleet Dashboard sort like the HMIB dashboards: click (or press Enter/Space on) a column header to sort and click again to reverse, in the card and in its maximize dialog
* issue: Right-align the Load, Charge, Time Left, Est. Power and Last Updated columns of the Fleet Dashboard UPSes table
* feature: Share the UPS Dashboard card arrangement across every UPS (graph cards stay per UPS since they belong to each device), hide N/A rows in the UPS Information card, combine Cable and Driver on one row, and add a per-UPS Estimated Power gauge card that reuses the shared nominal power x load % estimate
* issue: Show N/A for a slave UPS's (e.g. ONLINE SLAVE) estimated power on the Fleet Dashboard and leave it out of the fleet power total, since its draw is already counted in its master's

* feature: Estimate each UPS's power draw as nominal power x load % for UPSes that do not report real wattage, and show it on the Fleet Dashboard (an "Est. Power" tile, a new "Fleet Power" gauge card of total estimated watts against rated capacity, and an "Est. Power" column with a fleet total in the UPSes card) and as a sortable "Est. Power" column in the UPSes list
* feature: Make the Fleet Dashboard UPSes table sortable by UPS, Status, Load, Charge, Time Left, Est. Power and Last Updated; the choice persists in the browser and survives card refreshes
* feature: Make the Fleet Dashboard UPSes table sortable by UPS, Status, Load, Charge, Time Left, Est. Power and Last Updated
* issue: Stop the dashboard auto-refresh interval following the user to another page by driving Cacti's `refreshMSeconds`/`refreshPage` page-timer globals (as the Graphs page does) instead of storing the interval in the session
* feature: Auto-refresh now updates the dashboard's cards in place instead of reloading the whole page: through Cacti's `refreshFunction` page-timer hook where core has it (Cacti 1.3+), and with a timer of its own on Cacti 1.2.x, which has no such hook and stops when the dashboard leaves the screen. The chosen table sort is kept across a refresh (the live one, even if it was changed while the refresh was in flight), overlapping refresh rounds are skipped, and the full-page refresh remains the fallback when the dashboard script is not loaded
* issue: Mark a NUT UPS's linked Cacti host down when its NUT query fails (these devices have availability checking disabled, so core polling cannot detect it), and stop `upsd` from holding a poll open past the deadline by trickling bytes
* issue: Stop the UPS edit form from rewriting an existing UPS's port (3551 to 3493 or back) when it opens; the default port is now only swapped when the collector type is changed by hand
* issue: Store the start time, manufacture date, master update, last on battery and last self test of `apcupsd_ups_stats` as unknown (NULL) when the UPS does not report them, instead of letting each poll invent the current time
* security: Replace the confirmation pages' inline `onClick='cactiReturnTo()'` Cancel buttons with the CSP-safe `cactiReturnTo` class so the pages no longer trip Cacti's Content-Security-Policy script-src-attr directive
* security: Move the UPS filter selects' inline onChange handlers into the ready block so the page no longer trips Cacti's Content-Security-Policy script-src-attr directive
* dev: Enforce patch coverage of changed lines in CI and remove the inert COMPOSER_ROOT_VERSION env from the Pest step
Expand Down
2 changes: 1 addition & 1 deletion INFO
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[info]
name = apcupsd
version = 1.3.1
version = 1.4.0
longname = UPS Monitor Plugin for Cacti
author = The Cacti Group
email =
Expand Down
97 changes: 84 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
# apcupsd

This plugin is to be used to track UPS status from the `apcupsd` daemon as
well as SNMP enabled UPS'. The `apcupsd` daemon is able to provide information
on APC and other types of UPS' over various network typologies such as USB,
Modbus, Ethernet, etc. I have added basic SNMP support in order to provide
direct access to certain models over the SNMP protocol thus removing the need
for an `apcupsd` host to provide the monitoring details as well.
This plugin is to be used to track UPS status from the `apcupsd` daemon, from
the Network UPS Tools (NUT) `upsd` server, as well as from SNMP enabled UPS'.
The `apcupsd` daemon is able to provide information on APC and other types of
UPS' over various network typologies such as USB, Modbus, Ethernet, etc. NUT
provides the same for a very wide range of UPS vendors. I have added basic
SNMP support in order to provide direct access to certain models over the SNMP
protocol thus removing the need for an `apcupsd` host to provide the monitoring
details as well.

Each `apcupsd` UPS is defined by a network address and port name. Cacti uses
the `apcaccess` command to gather statistics from the UPS and store them
Expand All @@ -16,14 +18,19 @@ Cacti database can be used for Reporting, Graphing, and Alerting.

This plugin allows Cacti Administrators to easily track their Data Center
UPS's that do not support SNMP protocol, but that are supported by the
APCUPSD daemon.
APCUPSD daemon or by NUT.

## Features

* Track UPS status'

* Log information to Cacti database

* Three collector types: `apcupsd` (via `apcaccess`), SNMP, and NUT (via the
native NUT network protocol)

* Fleet and per-UPS dashboards, with sortable tables

## Cacti compatibility

If you are running a version of Cacti below 1.2.31, please add the function
Expand All @@ -41,25 +48,89 @@ $(document).off('click.cactiReturnTo', '.cactiReturnTo')
## Installation

Install just like any other plugin, just throw it in the plugin directory, and
Install and Enabled from the Plugin Management Interface. Your Cacti install
will require the Linux `apcupsd` package be installed and `apcaccess` be in the
system path.
Install and Enabled from the Plugin Management Interface. To monitor
`apcupsd` UPS', your Cacti install will require the Linux `apcupsd` package be
installed and `apcaccess` be in the system path. NUT UPS' need no extra
software on the Cacti poller.

After you have installed the plugin, install the Device Package in the
templates folder from Console > Import/Export > Import Package. This
Device Template will be used for showing available graphs.

## Monitoring UPS' with NUT

Support for Network UPS Tools (NUT) is new in version 1.4.0. The plugin talks
to the NUT `upsd` data server directly with a native PHP implementation of the
NUT network protocol, so the NUT client tools (`upsc`) do not have to be
installed on the Cacti poller, and `curl` is not involved. The only
requirement is that the poller can open a TCP connection to `upsd`, which
listens on port 3493 by default.

To add a NUT UPS, go to the UPSes page, add a UPS, and choose the `NUT Based`
type:

* **Hostname** and **TCP Port**: the host running `upsd` and its port (3493).

* **NUT UPS Name**: the name of the UPS on that server, as listed by
`upsc -l <host>` (the `ups` in `ups@host`). One `upsd` can serve several
UPS', so add one UPS here for each of them.

* **NUT Username** and **NUT Password**: optional. NUT servers have always
allowed anonymous read-only access and that is how they are normally
monitored, so leave these blank unless your `upsd.users` is set up to require
authentication. A user with no actions is enough, as the plugin only reads
data. The password is stored in the Cacti database the same way SNMP
community strings and passwords are.

* **Use TLS (STARTTLS)**: encrypts the connection before any credentials are
sent (the `openssl` PHP extension is required). The server certificate and
host name are verified, so by default the certificate must be trusted by the
Cacti poller. For a homelab with a self-signed certificate there are two
ways around that:

* **CA / Certificate File** (recommended): the full path, on the poller, to a
PEM file holding the CA certificate, or the self-signed server certificate
itself (for example `/etc/nut/upsd.pem` copied from the NUT server). The
server is still authenticated against that file, and the Hostname must
match a name in the certificate.

* **Allow Self-Signed Certificate**: accepts any certificate without
checking it. The connection is encrypted but the server's identity is not
verified, so a man-in-the-middle could still read the NUT credentials. Use
it only on a network you trust, and prefer the certificate file.

* **Timeout (seconds)**: how long the poller waits for the NUT server, from 1
to 120 seconds (5 by default). It bounds the connection attempt and each
reply, and the connection plus the whole conversation together never take
longer than twice the timeout, so an unresponsive server cannot hold up the
poller. The same setting applies to `apcupsd` UPS', where `apcaccess` is
stopped if it has not finished in time. SNMP UPS' keep using the SNMP
timeout.

On the NUT server, `upsd` only listens on localhost by default. To let a
Cacti poller reach it, add a `LISTEN` line to `upsd.conf` (for example
`LISTEN 0.0.0.0 3493`), restart `upsd`, and allow the poller through the
firewall.

NUT reports power state with short flags. These are translated into the
`apcupsd` vocabulary when the data is saved (`OL` becomes `ONLINE`, `OB` becomes
`ONBATT`, `LB` becomes `LOWBATT`, `RB` becomes `REPLACEBATT`, and `OVER`
becomes `OVERLOAD`), so the dashboards and fleet totals treat NUT and `apcupsd`
UPS' the same way. A Cacti device is created for each NUT UPS automatically,
the same as for `apcupsd` UPS'.

## Possible Bugs

If you figure out this problem, see the Cacti forums!

## Future Changes

Currently the SNMP based collection is functional but only covering APC UPS'.
I will likely fix that in the next release. Need some help from others.l
I will likely fix that in the next release. Need some help from others.

I've been looking at the NUT product to see if it's something I would add
support for down the line, but as of yet, I have not made that decision.
Measured real power (`ups.realpower`) is reported by many NUT UPS' but is not
stored yet; the plugin continues to estimate watts from the nominal power
rating and the load.

Got any ideas or complaints, please log an issue on GitHub.

Expand Down
41 changes: 19 additions & 22 deletions css/apcupsd.css
Original file line number Diff line number Diff line change
Expand Up @@ -524,36 +524,33 @@
white-space: nowrap;
}

/* Sortable column headers: the button inherits the header look and shows an
arrow for the active direction (exposed to assistive tech via aria-sort). */
.apcupsdDashSortBtn {
appearance: none;
background: none;
border: 0;
padding: 0;
margin: 0;
font: inherit;
font-weight: inherit;
color: inherit;
cursor: pointer;
text-align: inherit;
.apcupsdDashTable td.apcupsdDashNum,
.apcupsdDashTable th.apcupsdDashNum {
text-align: right;
white-space: nowrap;
}

.apcupsdDashSortBtn:hover,
.apcupsdDashSortBtn:focus-visible {
text-decoration: underline;
/* Sortable column headers (same behaviour as the HMIB dashboards): click or
press Enter/Space to sort; the arrow shows the active direction. */
.apcupsdDashTable th.apcupsdDashSortable {
cursor: pointer;
user-select: none;
}

.apcupsdDashSortable[aria-sort="ascending"] .apcupsdDashSortBtn::after {
content: " \25B2";
font-size: 0.75em;
.apcupsdDashTable th.apcupsdDashSortable:hover {
background: color-mix(in srgb, currentColor 8%, transparent);
}

.apcupsdDashSortable[aria-sort="descending"] .apcupsdDashSortBtn::after {
content: " \25BC";
font-size: 0.75em;
.apcupsdDashTable th.apcupsdDashSortable::after {
content: '\2195';
margin-left: 5px;
opacity: 0.4;
font-size: 10px;
}

.apcupsdDashTable th.apcupsdDashSortAsc::after { content: '\2191'; opacity: 0.9; }
.apcupsdDashTable th.apcupsdDashSortDesc::after { content: '\2193'; opacity: 0.9; }

/* Fleet total row under the UPSes table. */
.apcupsdDashTotalRow > td {
border-top: 2px solid color-mix(in srgb, currentColor 22%, transparent);
Expand Down
Loading
Loading