Files
unpoller_unpoller/main.go
T
Cody LeeandClaude Opus 5 d5dfc771d5 feat: add opt-in UNAS Pro support (closes #785)
Adds a new `unas` input plugin that polls UNAS Pro storage consoles and
exports console health, storage pools, disks and shares to Prometheus,
InfluxDB and DataDog.

UNAS is a separate plugin rather than a device type inside inputunifi
because a storage-only console has no Network application: it cannot
answer /status, has no sites, and shares none of the UniFi device schema.

The plugin is opt-in and inert until an operator names a console. Opt-in
is expressed as "no devices configured" rather than a `disable` flag,
because a bool named `disable` zero-values to false and so cannot make a
plugin default-off. Initialize returns silently on an empty device list
and, unlike inputunifi, nothing synthesizes a default URL.

Two behaviours are worth calling out for reviewers:

  - Metrics returns (metrics, nil) whenever any console was collected.
    poller.collectMetrics uses `if err != nil {} else if metric != nil`,
    so returning both would discard every healthy console because one
    failed. Only a total failure returns an error.

  - Re-auth fires on total failure, not on a 401. A mid-session 401 from
    GetData surfaces as ErrInvalidStatusCode, not ErrAuthenticationFailed,
    so there is no sentinel to match on. Session expiry fails all four
    endpoints at once, which is exactly the total-failure case.

Prometheus metrics use the `unifi_unas_` prefix, which diverges from the
`unas_` prefix used by the reference implementation; dashboards built
against that will need query edits.

Requires unifi/v5 v5.31.0 for the UNAS client and structs.

Credit to alexgreenbank/unaspoller for mapping the endpoints.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 07:52:37 -05:00

42 lines
910 B
Go

package main
//nolint:gci
import (
"log"
"os"
"time"
"github.com/unpoller/unpoller/pkg/poller"
// Load input plugins!
_ "github.com/unpoller/unpoller/pkg/inputunas"
_ "github.com/unpoller/unpoller/pkg/inputunifi"
// Load output plugins!
_ "github.com/unpoller/unpoller/pkg/datadogunifi"
_ "github.com/unpoller/unpoller/pkg/influxunifi"
_ "github.com/unpoller/unpoller/pkg/lokiunifi"
_ "github.com/unpoller/unpoller/pkg/otelunifi"
_ "github.com/unpoller/unpoller/pkg/promunifi"
)
// Keep it simple.
func main() {
// Set time zone based on TZ env variable.
setTimeZone(os.Getenv("TZ"))
if err := poller.New().Start(); err != nil {
log.Fatalln("[ERROR]", err)
}
}
func setTimeZone(timezone string) {
if timezone == "" {
return
}
var err error
if time.Local, err = time.LoadLocation(timezone); err != nil {
log.Printf("[ERROR] Loading TZ Location '%s': %v\n", timezone, err)
}
}