de5c39dddf8954348e58d4b31d48e5677e691af3
7
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
de5c39dddf |
Add an osTicket integration: list open tickets from its database
osTicket's own REST API only supports creating tickets, not listing or reading them, so this reads osTicket's MySQL/MariaDB database directly with a read-only user instead - the only integration in this app that isn't a REST API. Joins the ticket, status, priority, department, staff, team, and user tables, filtered to tickets in the "open" state (status names are customizable per install, but that state flag isn't). Surfaces per-ticket subject, priority, department, assignee, requester, and osTicket's own overdue/awaiting-reply flags, plus a page at /osticket and a Dashboard widget with open/overdue/awaiting-reply counts. Not verified against a live instance: unlike the HTTP-based integrations, there was no way to fake a MySQL server to test against in this environment, so the query is built from osTicket's published schema but has never actually run against a real database. See INTEGRATIONS.md for the read-only grant needed and further caveats. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
df2a5ce42b |
Add a Proxmox Backup Server integration: datastore/snapshot verification status
Proxmox VE already shows whether the last vzdump push to PBS succeeded, but has no visibility into PBS's own backup verification, GC/prune health, or host status. This adds PBS as its own integration (own adapter, page, nav entry, and Dashboard widget) that reads datastore usage and, for every stored snapshot, its verification state directly from PBS. A new daily check (mirroring the existing Proxmox backup-failure check) notifies when a snapshot has failed verification or a datastore couldn't be read, with its own toggle in Settings -> Notifications and its own maintenance-window silencing. Not verified against a live PBS instance — built from PBS's published API docs and a scratch test against a mocked PBS server exercising the adapter's parsing and auth-header format (PBSAPIToken uses a colon separator, unlike PVE's PVEAPIToken which uses =). See INTEGRATIONS.md for details and the "not verified" caveat. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
70ba60c7da |
Add a phpIPAM import to the IP Addresses page
New "Sync from phpIPAM" action on IP Addresses, alongside the existing
"Sync from Tailscale" / "Sync from Proxmox" ones and built the same way:
a new integration type (config in-app, URL + API app ID + app token,
credentials encrypted at rest) that this page pulls from on demand.
Deliberately import-only, not a full integration -- no dedicated page,
dashboard widget, or nav entry, since that's all this was asked for.
Auth is phpIPAM's static "App token" method: create an API app under
Administration -> API with its security set to "SSL with App token", and
its one-time code goes straight in as the `token` header (also sent as
`phpipam-token`, in case a given version expects that name instead) --
no login call, no token to renew. The user/password "User token" method
isn't implemented.
Addresses are read the standard way: GET /subnets/, then GET
/subnets/{id}/addresses/ for each, rather than assuming a single
"all addresses" endpoint exists on every version. phpIPAM wraps every
response as {code, success, data} -- including an empty result: a subnet
with nothing in it answers success:false, message:"No addresses found"
rather than success:true, data:[]. That's read as "nothing here", not a
failure; anything else with success:false throws with phpIPAM's own
message. One subnet failing outright (e.g. the app lacks permission on
it) is skipped with a note rather than aborting the whole sync. Every
address field is read defensively -- optional, independently
type-checked -- so a field phpIPAM renames or drops in some version
leaves that value blank instead of breaking the import.
Imported entries: label from hostname or description, "phpIPAM" as
vendor, the subnet's own description (or its CIDR, if it has none) as
location, and description/note/MAC folded into notes. Existing sync
plumbing (upsertSyncedEntry) gained a location parameter so this and any
future sync can set it; the two existing syncs pass null, unchanged.
Endpoints, the token header, and the address/subnet field names are
cross-checked against phpIPAM's own published API documentation. Not
verified against a live instance -- there wasn't one available while
building this, so if a real sync comes back empty or with the wrong
fields, that's the next thing to check.
Verified with 23 backend checks against a fake phpIPAM server matching
that documented shape (the empty-subnet quirk, a subnet that fails
outright, malformed/missing fields, a non-JSON response) and the real
route (added/updated/skipped counts, a manually-entered IP never
overwritten, roles, no-enabled-integration, upstream failure surfaced
per-integration rather than as a 500, audit entries) plus a browser check
of the real IP Addresses page against the real routers: the sync button,
its result message, re-syncing (updates rather than duplicates), the
manual entry staying untouched, and the viewer view.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
||
|
|
bf7f73f6b6 |
Import maintenance windows from Uptime Kuma
New "Import from Uptime Kuma" action on the Maintenance page (operator):
pick an Uptime Kuma integration and a duration, and it starts (or
extends) a maintenance window here for every server whose address
matches a monitor Uptime Kuma currently reports as being in maintenance,
reusing the existing monitor-to-server matching from the Uptime Kuma
integration itself.
Uptime Kuma's metrics endpoint only exposes a monitor's *current* status,
not its scheduled start/end time (there's no API for that), so this
deliberately doesn't try to mirror Uptime Kuma's own schedule -- it starts
a window for the duration you choose, the same bounded/required-end
window this feature has always used. Running it again while Kuma is
still in maintenance extends the same window rather than stacking a
second one; when Kuma later shows nothing in maintenance, already-active
windows are left alone rather than force-ended, since ending them isn't
something only Uptime Kuma's state should decide. Two Kuma monitors that
match the same server are deduped to one window. Monitors with no
matching server are reported back by name so nothing is silently missed,
and monitors that aren't in maintenance are ignored entirely.
The manual "Start maintenance" endpoint's start-or-extend logic (dedupe,
pruning old rows, the response shape) is now a shared
services/maintenance.ts function instead of living only in that route
handler, so the import path can't drift from how a manual window behaves.
Likewise the server-matching helper gained a small toMatchableServers()
so the existing Uptime Kuma monitors route and this new one build the
same match input the same way instead of each parsing server rows on
their own.
No schema change -- imported windows are ordinary maintenance windows;
their Uptime-Kuma origin is only in the reason text ("Imported from
Uptime Kuma (<integration>): <monitor>"), visible in the Active table and
the audit log like any other window.
Verified with 28 backend checks (the refactored manual start/extend
flow as a regression check; roles; unknown/wrong-type/disabled
integration; validation; nothing-in-maintenance; matching including
same-server dedup and unmatched monitors; re-running extends rather than
duplicating; windows left alone once Kuma exits maintenance; upstream
failure; audit entries) and by driving the real Maintenance page against
the real routers in a browser: import, re-import (extends), the
nothing-in-maintenance state, and the viewer view (no edit card, active
windows still visible). Real dev database mtime untouched.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
||
|
|
1a2dd19736 |
Add an Uptime Kuma integration: monitor status and which server each one watches
New integration, following the existing pattern: config in-app (URL + API key, credentials encrypted at rest), its own Uptime Kuma page, an Integrations list entry, a Dashboard widget, and diagnostic-log/ integration-down-alert coverage for free via the shared withDiagLogging wrapper. Read-only -- no start/stop equivalent exists for a monitor. Uptime Kuma has no conventional REST API (the dashboard talks to it over Socket.IO); researched before writing any code, since guessing wrong here would have cost real time. The one machine-readable, authenticated endpoint that lists every monitor is its Prometheus exporter at GET /metrics, gated by HTTP Basic auth -- an API key as the password with the username left blank on current installs, or the real dashboard login on installs from before the API-key feature existed. This adapter authenticates the same way and parses that endpoint's text-exposition format itself (metrics: monitor_status, monitor_response_time, monitor_cert_days_remaining, monitor_uptime_ratio; labels: monitor_id, monitor_name, monitor_type, monitor_url, monitor_hostname, monitor_port), verified against the documented metric/label set and the actual upstream source (server/prometheus.js). A malformed line is skipped rather than failing the whole scrape. "What server is being monitored for what": each monitor's target (an IP for TCP checks, or the hostname out of the URL for HTTP/keyword checks) is matched against your servers' own IPs and hostnames -- reusing the same kind of match already used in the consistency report -- and linked to that server's page. Monitors with no single network target (groups, push monitors, DNS/keyword checks with a complex URL) are left unmatched rather than guessed at. Uptime Kuma's tags aren't read, since the Prometheus endpoint doesn't reliably distinguish a tag label from any other label it might add later. The username field is the first genuinely optional integration config field this app has had; IntegrationField gained an `optional` flag (server validation and both the add/edit web forms honor it) rather than special-casing Uptime Kuma. Verified with 48 backend checks (Prometheus text parsing including escaped quotes, decimals, negative numbers, and malformed lines; TCP vs. HTTP target/port extraction; every documented status code; server matching by IP, hostname, and short name, including no-match cases; the route's real HTTP round trip against a fake Uptime Kuma server, wrong credentials, upstream failures, roles, wrong/disabled/missing integration, diagnostic-log entries; the optional-field validation rule) and by driving the real page and the real Dashboard widget in a browser against the real routers, including CSV export and column sorting. Real dev database mtime untouched. Not verified: a real Uptime Kuma instance. Everything here was checked against Uptime Kuma's documented metric format, its actual upstream source, and a fake server built to match both -- not against a live installation. If your instance's /metrics output differs from what's documented (older version, unusual monitor types), the parser should degrade to an empty or partial monitor list rather than error, but that degradation itself hasn't been observed against the real thing. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
99db7e1cf0 |
Surface Proxmox backup job status, with a daily failure notification
Proxmox already runs vzdump backups, but nothing in the app said
whether they were actually succeeding — a silent backup failure is
one of the more dangerous blind spots a homelab admin can have. Adds
a "Backups" card to the Proxmox page: configured backup job
schedules (storage target, which guests, enabled/disabled) from
GET /cluster/backup, and recent vzdump task history per node from
GET /nodes/{node}/tasks?typefilter=vzdump, with a banner at the top
if the most recent run didn't succeed.
New "Proxmox backup failed" notification toggle under Settings ->
Notifications, on the same daily schedule as the other checks. The
scheduler checks each node's own most-recent vzdump run independently
(not just the single most recent task overall) so one node's healthy
backup can't mask another node's failing one in a multi-node cluster.
Known limitation, documented in the adapter's own header comment:
Proxmox's task list doesn't reliably expose which specific guest
failed within an "all guests" job — only the task's own log text has
that — so this surfaces job- and task-level status rather than
guessing at per-guest outcomes.
Verified against a fake Proxmox server (real self-signed HTTPS, since
the adapter's node:https usage can't be monkey-patched under ESM)
reproducing the documented /cluster/backup and task-list response
shapes: job parsing (all-guests+exclude vs specific-vmids+disabled)
correct, task OK/failure parsing correct, and the critical multi-node
scenario confirmed — one node's failing latest run flagged, the
other's healthy latest run correctly left alone, with exactly one
notification of the right content. This reproduces Proxmox's
documented API shape rather than a live-verified one; flag if the
real cluster's response differs in some way this didn't anticipate.
Confirmed the real dev database's mtime was untouched throughout.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
||
|
|
af3f7e77d2 |
Document required access per integration and DNS provider
Each adapter performs write actions, not just reads (start/stop a guest, edit a DNS record, rerun a CI job, etc.), so a read-only credential silently works for the dashboard views but fails the moment you use an action. Lists the exact endpoints/permissions needed per target system, drawn from each adapter's own auth code and header comments (e.g. Proxmox's Sys.Audit/Datastore.Audit split, Azure's DNS Zone Contributor role, Loopia/Pi-hole/cPanel having no scoped-credential option at all). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |