diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index a1741c1ac..4643dd3d6 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -8,7 +8,7 @@ frontend. ## 🏗 High-Level Overview -The system runs as a single binary that serves both the API and the embedded frontend assets. It connects to infrastructure via platform-specific REST APIs and lightweight push-based agents, normalises everything into a **Unified Resource model**, and delivers real-time updates to clients over WebSocket. +The system runs as a single binary that serves both the API and the embedded frontend assets. It connects to infrastructure via platform-supported HTTP and WebSocket APIs and lightweight push-based agents, normalises everything into a **Unified Resource model**, and delivers real-time updates to clients over WebSocket. ```mermaid flowchart TD @@ -66,7 +66,10 @@ All backend code lives under `cmd/`, `internal/`, and `pkg/`. The binary is asse 3. **Monitoring Engine (`internal/monitoring`)** - **Polymorphic monitors**: Each Proxmox VE/PBS/PMG node runs in its own goroutine, polling via the platform REST API. - **Agent receivers** (`internal/api`): Docker, Host, and Kubernetes agents push metrics via HTTP POST to `/api/agents/{type}/report`. - - **TrueNAS provider** (`internal/truenas`): Polls TrueNAS REST API for system info, pools, datasets, disks, alerts, ZFS snapshots, and replication tasks. + - **TrueNAS provider** (`internal/truenas`): Uses the versioned JSON-RPC 2.0 + WebSocket API on supported SCALE releases for system info, pools, + datasets, disks, alerts, ZFS snapshots, and replication tasks. A + version-gated REST path remains only for legacy SCALE and CORE systems. - Enterprise/internal multi-org aware: when `PULSE_MULTI_TENANT_ENABLED=true`, each organisation gets a separate shared-process monitor namespace with its own configuration. 4. **WebSocket Hub (`internal/websocket`)** @@ -127,7 +130,9 @@ All backend code lives under `cmd/`, `internal/`, and `pkg/`. The binary is asse 1. **Collection**: - **Proxmox VE / PBS / PMG**: Monitoring engine polls platform REST APIs (configurable interval, default 2 s for PVE). - **Docker / Host / Kubernetes**: Lightweight agents push metrics via HTTP POST on their configured interval. - - **TrueNAS**: Provider polls the TrueNAS REST API for system, pool, dataset, disk, alert, and replication data. + - **TrueNAS**: Provider polls the versioned JSON-RPC WebSocket API on + supported SCALE releases, with REST compatibility limited to recognized + legacy SCALE and CORE systems. 2. **Normalisation**: Platform-specific responses are mapped into `unifiedresources.Resource` structs by adapters in `internal/unifiedresources/adapters.go`. 3. **Registration**: Resources are inserted into the in-memory registry, which handles deduplication, identity matching, and status computation. 4. **Broadcast**: The latest state snapshot is serialised to JSON and pushed to all connected WebSocket clients by the Hub. diff --git a/docs/TROUBLESHOOTING.md b/docs/TROUBLESHOOTING.md index aeb53c96a..95c9aac2f 100644 --- a/docs/TROUBLESHOOTING.md +++ b/docs/TROUBLESHOOTING.md @@ -193,12 +193,13 @@ repair an older generated unit rather than adding a JSON-parsing wrapper. ### TrueNAS #### "TrueNAS service unavailable" -- Ensure TrueNAS was added in **Settings → TrueNAS** with a valid URL and API key. -- Check that the TrueNAS system is reachable from the Pulse server (default HTTPS port). -- Verify the API key has read access. Test with: - ```bash - curl -sk -H "Authorization: Bearer " https:///api/v2.0/system/info - ``` +- Ensure TrueNAS was added in **Settings → TrueNAS** with a valid HTTPS URL, + API key, and the username that owns the key. +- Check that the TrueNAS system is reachable from the Pulse server (default + HTTPS port). +- Verify the API-key owner has read access, then use **Test Connection** in + Pulse. TrueNAS 25.04 and later should report the `jsonrpc-websocket` + transport; TrueNAS 26 removed the former `/api/v2.0` REST endpoints. #### TrueNAS pools/datasets not appearing - TrueNAS data appears in the unified resource model and may take one polling cycle (30s) to appear. diff --git a/docs/TRUENAS.md b/docs/TRUENAS.md index 880dfe1de..13ef48257 100644 --- a/docs/TRUENAS.md +++ b/docs/TRUENAS.md @@ -6,7 +6,8 @@ Pulse v6 includes first-class monitoring for **TrueNAS SCALE** and **TrueNAS COR 1. Go to **Settings → TrueNAS**. 2. Click **Add Connection**. -3. Enter the TrueNAS URL (e.g., `https://truenas.local`) and an API key. +3. Enter the TrueNAS URL (e.g., `https://truenas.local`), the API key, and the + username that owns the key. 4. Click **Test Connection** → **Save**. 5. Data appears within one polling cycle (~30 seconds). @@ -19,10 +20,11 @@ On your TrueNAS system: 3. Copy the key value and paste it into Pulse. > **Tip**: Pulse uses the supported JSON-RPC WebSocket API on TrueNAS 25.04 -> and later. API keys inherit the linked user's roles, so the user must be able -> to read the methods Pulse polls. Native app control actions require the -> corresponding TrueNAS app permissions. Legacy releases continue to use the -> version-gated REST compatibility path. +> and later. TrueNAS 26 removes the former REST API entirely. API keys inherit +> the linked user's roles, so enter the key owner's username and ensure that +> user can read the methods Pulse polls. Native app control actions require the +> corresponding TrueNAS app permissions. Recognized legacy SCALE and CORE +> releases continue to use the version-gated REST compatibility path. ## What Gets Monitored @@ -93,7 +95,7 @@ All endpoints require admin authentication. curl -X POST http://localhost:7655/api/truenas/connections \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ - -d '{"name":"nas-1","host":"https://truenas.local","api_key":"your-api-key"}' + -d '{"name":"nas-1","host":"https://truenas.local","username":"key-owner","apiKey":"your-api-key"}' ``` ### Testing a connection (API) @@ -102,18 +104,21 @@ curl -X POST http://localhost:7655/api/truenas/connections \ curl -X POST http://localhost:7655/api/truenas/connections/test \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ - -d '{"name":"nas-1","host":"https://truenas.local","api_key":"your-api-key"}' + -d '{"name":"nas-1","host":"https://truenas.local","username":"key-owner","apiKey":"your-api-key"}' ``` ## Troubleshooting ### "TrueNAS service unavailable" + - Check that the TrueNAS system is reachable from the Pulse server. -- Verify the URL includes the protocol (`https://`). -- Test connectivity manually: - ```bash - curl -sk -H "Authorization: Bearer " https:///api/v2.0/system/info - ``` +- Verify the URL uses `https://`. Current TrueNAS releases require TLS for + remote API-key authentication. +- Verify that the configured username owns the API key and has permission to + read the monitored methods. +- Use **Test Connection** in Pulse. The connection's transport diagnostics + should report `jsonrpc-websocket` for TrueNAS 25.04 and later; do not test a + current appliance through the removed `/api/v2.0` REST endpoints. ### No data appearing after adding connection - Wait at least 30 seconds for the first poll cycle. @@ -138,6 +143,8 @@ Set `PULSE_ENABLE_TRUENAS=false` and restart Pulse. Existing connection data is ## See Also +- [TrueNAS API Reference](https://www.truenas.com/docs/scale/api/) — current + JSON-RPC transport, API-key, and TLS requirements - [Configuration Guide](CONFIGURATION.md#truenas) — environment variables and setup - [ZFS Monitoring](ZFS_MONITORING.md) — Proxmox-native ZFS pool monitoring - [Recovery](RECOVERY.md) — TrueNAS snapshots in the recovery view diff --git a/frontend-modern/public/docs/ARCHITECTURE.md b/frontend-modern/public/docs/ARCHITECTURE.md index a1741c1ac..4643dd3d6 100644 --- a/frontend-modern/public/docs/ARCHITECTURE.md +++ b/frontend-modern/public/docs/ARCHITECTURE.md @@ -8,7 +8,7 @@ frontend. ## 🏗 High-Level Overview -The system runs as a single binary that serves both the API and the embedded frontend assets. It connects to infrastructure via platform-specific REST APIs and lightweight push-based agents, normalises everything into a **Unified Resource model**, and delivers real-time updates to clients over WebSocket. +The system runs as a single binary that serves both the API and the embedded frontend assets. It connects to infrastructure via platform-supported HTTP and WebSocket APIs and lightweight push-based agents, normalises everything into a **Unified Resource model**, and delivers real-time updates to clients over WebSocket. ```mermaid flowchart TD @@ -66,7 +66,10 @@ All backend code lives under `cmd/`, `internal/`, and `pkg/`. The binary is asse 3. **Monitoring Engine (`internal/monitoring`)** - **Polymorphic monitors**: Each Proxmox VE/PBS/PMG node runs in its own goroutine, polling via the platform REST API. - **Agent receivers** (`internal/api`): Docker, Host, and Kubernetes agents push metrics via HTTP POST to `/api/agents/{type}/report`. - - **TrueNAS provider** (`internal/truenas`): Polls TrueNAS REST API for system info, pools, datasets, disks, alerts, ZFS snapshots, and replication tasks. + - **TrueNAS provider** (`internal/truenas`): Uses the versioned JSON-RPC 2.0 + WebSocket API on supported SCALE releases for system info, pools, + datasets, disks, alerts, ZFS snapshots, and replication tasks. A + version-gated REST path remains only for legacy SCALE and CORE systems. - Enterprise/internal multi-org aware: when `PULSE_MULTI_TENANT_ENABLED=true`, each organisation gets a separate shared-process monitor namespace with its own configuration. 4. **WebSocket Hub (`internal/websocket`)** @@ -127,7 +130,9 @@ All backend code lives under `cmd/`, `internal/`, and `pkg/`. The binary is asse 1. **Collection**: - **Proxmox VE / PBS / PMG**: Monitoring engine polls platform REST APIs (configurable interval, default 2 s for PVE). - **Docker / Host / Kubernetes**: Lightweight agents push metrics via HTTP POST on their configured interval. - - **TrueNAS**: Provider polls the TrueNAS REST API for system, pool, dataset, disk, alert, and replication data. + - **TrueNAS**: Provider polls the versioned JSON-RPC WebSocket API on + supported SCALE releases, with REST compatibility limited to recognized + legacy SCALE and CORE systems. 2. **Normalisation**: Platform-specific responses are mapped into `unifiedresources.Resource` structs by adapters in `internal/unifiedresources/adapters.go`. 3. **Registration**: Resources are inserted into the in-memory registry, which handles deduplication, identity matching, and status computation. 4. **Broadcast**: The latest state snapshot is serialised to JSON and pushed to all connected WebSocket clients by the Hub. diff --git a/frontend-modern/public/docs/TROUBLESHOOTING.md b/frontend-modern/public/docs/TROUBLESHOOTING.md index aeb53c96a..95c9aac2f 100644 --- a/frontend-modern/public/docs/TROUBLESHOOTING.md +++ b/frontend-modern/public/docs/TROUBLESHOOTING.md @@ -193,12 +193,13 @@ repair an older generated unit rather than adding a JSON-parsing wrapper. ### TrueNAS #### "TrueNAS service unavailable" -- Ensure TrueNAS was added in **Settings → TrueNAS** with a valid URL and API key. -- Check that the TrueNAS system is reachable from the Pulse server (default HTTPS port). -- Verify the API key has read access. Test with: - ```bash - curl -sk -H "Authorization: Bearer " https:///api/v2.0/system/info - ``` +- Ensure TrueNAS was added in **Settings → TrueNAS** with a valid HTTPS URL, + API key, and the username that owns the key. +- Check that the TrueNAS system is reachable from the Pulse server (default + HTTPS port). +- Verify the API-key owner has read access, then use **Test Connection** in + Pulse. TrueNAS 25.04 and later should report the `jsonrpc-websocket` + transport; TrueNAS 26 removed the former `/api/v2.0` REST endpoints. #### TrueNAS pools/datasets not appearing - TrueNAS data appears in the unified resource model and may take one polling cycle (30s) to appear. diff --git a/frontend-modern/public/docs/TRUENAS.md b/frontend-modern/public/docs/TRUENAS.md index 880dfe1de..13ef48257 100644 --- a/frontend-modern/public/docs/TRUENAS.md +++ b/frontend-modern/public/docs/TRUENAS.md @@ -6,7 +6,8 @@ Pulse v6 includes first-class monitoring for **TrueNAS SCALE** and **TrueNAS COR 1. Go to **Settings → TrueNAS**. 2. Click **Add Connection**. -3. Enter the TrueNAS URL (e.g., `https://truenas.local`) and an API key. +3. Enter the TrueNAS URL (e.g., `https://truenas.local`), the API key, and the + username that owns the key. 4. Click **Test Connection** → **Save**. 5. Data appears within one polling cycle (~30 seconds). @@ -19,10 +20,11 @@ On your TrueNAS system: 3. Copy the key value and paste it into Pulse. > **Tip**: Pulse uses the supported JSON-RPC WebSocket API on TrueNAS 25.04 -> and later. API keys inherit the linked user's roles, so the user must be able -> to read the methods Pulse polls. Native app control actions require the -> corresponding TrueNAS app permissions. Legacy releases continue to use the -> version-gated REST compatibility path. +> and later. TrueNAS 26 removes the former REST API entirely. API keys inherit +> the linked user's roles, so enter the key owner's username and ensure that +> user can read the methods Pulse polls. Native app control actions require the +> corresponding TrueNAS app permissions. Recognized legacy SCALE and CORE +> releases continue to use the version-gated REST compatibility path. ## What Gets Monitored @@ -93,7 +95,7 @@ All endpoints require admin authentication. curl -X POST http://localhost:7655/api/truenas/connections \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ - -d '{"name":"nas-1","host":"https://truenas.local","api_key":"your-api-key"}' + -d '{"name":"nas-1","host":"https://truenas.local","username":"key-owner","apiKey":"your-api-key"}' ``` ### Testing a connection (API) @@ -102,18 +104,21 @@ curl -X POST http://localhost:7655/api/truenas/connections \ curl -X POST http://localhost:7655/api/truenas/connections/test \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ - -d '{"name":"nas-1","host":"https://truenas.local","api_key":"your-api-key"}' + -d '{"name":"nas-1","host":"https://truenas.local","username":"key-owner","apiKey":"your-api-key"}' ``` ## Troubleshooting ### "TrueNAS service unavailable" + - Check that the TrueNAS system is reachable from the Pulse server. -- Verify the URL includes the protocol (`https://`). -- Test connectivity manually: - ```bash - curl -sk -H "Authorization: Bearer " https:///api/v2.0/system/info - ``` +- Verify the URL uses `https://`. Current TrueNAS releases require TLS for + remote API-key authentication. +- Verify that the configured username owns the API key and has permission to + read the monitored methods. +- Use **Test Connection** in Pulse. The connection's transport diagnostics + should report `jsonrpc-websocket` for TrueNAS 25.04 and later; do not test a + current appliance through the removed `/api/v2.0` REST endpoints. ### No data appearing after adding connection - Wait at least 30 seconds for the first poll cycle. @@ -138,6 +143,8 @@ Set `PULSE_ENABLE_TRUENAS=false` and restart Pulse. Existing connection data is ## See Also +- [TrueNAS API Reference](https://www.truenas.com/docs/scale/api/) — current + JSON-RPC transport, API-key, and TLS requirements - [Configuration Guide](CONFIGURATION.md#truenas) — environment variables and setup - [ZFS Monitoring](ZFS_MONITORING.md) — Proxmox-native ZFS pool monitoring - [Recovery](RECOVERY.md) — TrueNAS snapshots in the recovery view diff --git a/scripts/check_public_docs.py b/scripts/check_public_docs.py index be2bc98d7..4d119a092 100644 --- a/scripts/check_public_docs.py +++ b/scripts/check_public_docs.py @@ -37,6 +37,10 @@ MISLEADING_PUBLIC_CLAIMS = { "dead-man direction is reversed; Pulse sends its own health signal to an " "external watchdog" ), + r"api/v2\.0/system/info": ( + "TrueNAS 26 removed the legacy REST system-info endpoint; current " + "troubleshooting must use Pulse's JSON-RPC connection test" + ), } diff --git a/scripts/tests/test_public_docs_claims.py b/scripts/tests/test_public_docs_claims.py index 1dfaeb9e1..6accfdf3f 100644 --- a/scripts/tests/test_public_docs_claims.py +++ b/scripts/tests/test_public_docs_claims.py @@ -54,6 +54,20 @@ class PublicDocsClaimsTest(unittest.TestCase): self.assertEqual(errors, []) + def test_rejects_removed_truenas_rest_probe(self) -> None: + with tempfile.TemporaryDirectory() as temporary: + root = Path(temporary) + note = root / "note.md" + note.write_text( + "Test with https://nas.local/api/v2.0/system/info.\n", + encoding="utf-8", + ) + with mock.patch.object(public_docs, "ROOT", root): + errors = public_docs.check_public_claims([note]) + + self.assertEqual(len(errors), 1) + self.assertIn("TrueNAS 26 removed", errors[0]) + if __name__ == "__main__": unittest.main()