mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-23 20:25:56 +00:00
Point monitoring help at the current platform navigation
Replace retired task-page advice with registered platform routes, TrueNAS tabs and Proxmox backups. Preserve saved connections when troubleshooting missing navigation and distinguish proxy reload failures from missing inventory. Change-source: pulse-maintainer
This commit is contained in:
+3
-2
@@ -152,7 +152,7 @@ It does **not** allow:
|
||||
|
||||
If you have multiple PBS servers, add each one separately in Settings. Pulse will:
|
||||
- Monitor each server independently
|
||||
- Show backups from all servers in the unified Recovery view
|
||||
- Show backups from all servers under **Proxmox → Backups** (`/proxmox/backups`)
|
||||
- Deduplicate if the same backup appears via both PVE passthrough and direct PBS
|
||||
|
||||
---
|
||||
@@ -301,7 +301,8 @@ or change retention to hide a display problem.
|
||||
|
||||
## Data Source Indicator
|
||||
|
||||
In the Recovery view, PBS backups show a data source indicator:
|
||||
Under **Proxmox → Backups** (`/proxmox/backups`), PBS backups show a data source
|
||||
indicator. There is no current top-level Recovery page:
|
||||
|
||||
- **"PBS"** badge alone = Direct PBS connection (full data)
|
||||
- **"PBS via PVE"** = Passthrough via PVE storage (limited data)
|
||||
|
||||
+37
-4
@@ -413,7 +413,7 @@ consequential, manually redacted error.
|
||||
### TrueNAS
|
||||
|
||||
#### "TrueNAS service unavailable"
|
||||
- Ensure TrueNAS was added in **Settings → TrueNAS** with a valid HTTPS URL,
|
||||
- Ensure TrueNAS was added in **Settings → Infrastructure → Platform connections** 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).
|
||||
@@ -424,7 +424,10 @@ consequential, manually redacted error.
|
||||
#### TrueNAS pools/datasets not appearing
|
||||
- TrueNAS data appears in the unified resource model and may take one configured
|
||||
polling cycle (60 seconds by default) to appear.
|
||||
- Check **Infrastructure** (TrueNAS host), **Storage** (pools/datasets), and **Recovery** (snapshots/replication).
|
||||
- Open **TrueNAS → Overview** for the appliance, **TrueNAS → Storage**
|
||||
(`/truenas/storage`) for pools, datasets and disks, and **TrueNAS → Protection**
|
||||
(`/truenas/protection`) for snapshots and replication. These are tabs within
|
||||
TrueNAS, not separate top-level Storage or Recovery pages.
|
||||
- For data that stops refreshing, use the [TrueNAS polling checks](TRUENAS.md#stale-truenas-data)
|
||||
before testing or restarting. A stale badge is not proof of an invalid key,
|
||||
and a successful connection test is not proof that collection has recovered.
|
||||
@@ -432,8 +435,38 @@ consequential, manually redacted error.
|
||||
### Navigation (v6)
|
||||
|
||||
#### Old bookmarks don't work
|
||||
- Legacy URLs (`/proxmox`, `/docker`, `/kubernetes`, `/hosts`, `/services`) are not supported in v6.
|
||||
- Update bookmarks to canonical routes. See [Migration Guide](MIGRATION_UNIFIED_NAV.md).
|
||||
|
||||
Current Pulse uses platform navigation. `/proxmox`, `/docker` and `/kubernetes`
|
||||
are supported; do not replace them with the retired task-based routes.
|
||||
Open Pulse at its base URL and use the menu to find the relevant page:
|
||||
|
||||
| Menu | Entry route |
|
||||
| --- | --- |
|
||||
| Proxmox | `/proxmox/overview` |
|
||||
| Docker | `/docker/overview` |
|
||||
| Kubernetes | `/kubernetes/overview` |
|
||||
| TrueNAS | `/truenas/overview` |
|
||||
| vSphere | `/vmware/overview` |
|
||||
| Machines | `/standalone/machines` |
|
||||
|
||||
The short-lived top-level `/workloads`, `/storage` and `/recovery` layout is
|
||||
retired. `/infrastructure` now opens the default workspace, not the former
|
||||
unified host page. For old `/hosts` or `/services` bookmarks, select the current
|
||||
platform or Machines page instead of assuming an automatic redirect. PBS
|
||||
backups are under **Proxmox → Backups**, and TrueNAS snapshots and replication
|
||||
are under **TrueNAS → Protection**.
|
||||
|
||||
Platform-connected hosts can appear under their platform rather than Machines.
|
||||
If a menu or expected resource is missing, check its saved connection and last
|
||||
successful collection in **Settings → Infrastructure**; a missing page alone
|
||||
does not prove a host was deleted. Do not delete connections or re-enrol agents
|
||||
just to repair a bookmark.
|
||||
|
||||
If menu navigation works but reloading the same URL returns a proxy 404, check
|
||||
the proxy's route handling using [Reverse Proxy Configuration](REVERSE_PROXY.md).
|
||||
For the current layout, see [FAQ](FAQ.md#how-is-navigation-organised-in-pulse-v6).
|
||||
The [unified-navigation migration](MIGRATION_UNIFIED_NAV.md) is historical,
|
||||
not a guide to the current menu.
|
||||
|
||||
### Relay / Mobile
|
||||
|
||||
|
||||
+24
-19
@@ -4,8 +4,9 @@ Pulse v6 includes first-class monitoring for **TrueNAS SCALE** and **TrueNAS COR
|
||||
|
||||
## Quick Start
|
||||
|
||||
1. Go to **Settings → TrueNAS**.
|
||||
2. Click **Add Connection**.
|
||||
1. Go to **Settings → Infrastructure**.
|
||||
2. Click **Add infrastructure** and choose **TrueNAS**. Existing connections
|
||||
are listed under **Platform connections**.
|
||||
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**.
|
||||
@@ -28,27 +29,27 @@ On your TrueNAS system:
|
||||
|
||||
## What Gets Monitored
|
||||
|
||||
| Data | Unified Page | Details |
|
||||
| Data | Pulse page / tab | Details |
|
||||
|---|---|---|
|
||||
| System info (hostname, version, uptime) | Infrastructure | CPU, memory, health status |
|
||||
| Virtual machines | TrueNAS Overview | State, CPU, memory, boot mode, devices, and security flags from the TrueNAS VM API |
|
||||
| Apps | TrueNAS Overview | Native app state, image/version, ports, volumes, networks, and runtime container details |
|
||||
| ZFS Pools | Storage | Total/used/free capacity, pool status (ONLINE/DEGRADED/FAULTED) |
|
||||
| ZFS Datasets | Storage | Used/available space, mount status, read-only flag |
|
||||
| Physical Disks | Storage | Model, serial, size, transport type, rotational flag, temperature, and native SMART failure/counter evidence when TrueNAS reports it |
|
||||
| ZFS Snapshots | Recovery | Dataset, creation time, size, referenced data |
|
||||
| Replication Tasks | Recovery | Source/target datasets, direction, last run status |
|
||||
| System info (hostname, version, uptime) | TrueNAS → Overview | CPU, memory, health status |
|
||||
| Virtual machines | TrueNAS → VMs | State, CPU, memory, boot mode, devices, and security flags from the TrueNAS VM API |
|
||||
| Apps | TrueNAS → Apps | Native app state, image/version, ports, volumes, networks, and runtime container details |
|
||||
| ZFS Pools | TrueNAS → Storage | Total/used/free capacity, pool status (ONLINE/DEGRADED/FAULTED) |
|
||||
| ZFS Datasets | TrueNAS → Storage | Used/available space, mount status, read-only flag |
|
||||
| Physical Disks | TrueNAS → Storage | Model, serial, size, transport type, rotational flag, temperature, and native SMART failure/counter evidence when TrueNAS reports it |
|
||||
| ZFS Snapshots | TrueNAS → Protection | Dataset, creation time, size, referenced data |
|
||||
| Replication Tasks | TrueNAS → Protection | Source/target datasets, direction, last run status |
|
||||
| TrueNAS Alerts | Alerts | Native TrueNAS alert messages and severity levels |
|
||||
|
||||
## Unified Resource Mapping
|
||||
|
||||
TrueNAS resources are mapped into the unified resource model:
|
||||
|
||||
- **TrueNAS host** → appears as a resource with `source: truenas` on the **Infrastructure** page.
|
||||
- **TrueNAS VMs** → appear as canonical `vm` workloads on the **TrueNAS** page.
|
||||
- **TrueNAS apps** → appear as canonical `app-container` workloads on the **TrueNAS** page.
|
||||
- **ZFS pools and datasets** → appear on the **Storage** page.
|
||||
- **ZFS snapshots and replication** → appear on the **Recovery** page as recovery points.
|
||||
- **TrueNAS host** → appears as a resource with `source: truenas` under **TrueNAS → Overview** (`/truenas/overview`).
|
||||
- **TrueNAS VMs** → appear as canonical `vm` workloads under **TrueNAS → VMs** (`/truenas/vms`).
|
||||
- **TrueNAS apps** → appear as canonical `app-container` workloads under **TrueNAS → Apps** (`/truenas/apps`).
|
||||
- **ZFS pools, datasets and physical disks** → appear under **TrueNAS → Storage** (`/truenas/storage`).
|
||||
- **ZFS snapshots and replication** → appear under **TrueNAS → Protection** (`/truenas/protection`) as recovery points.
|
||||
- **TrueNAS alerts** → surfaced on the **Alerts** page alongside Proxmox and other platform alerts.
|
||||
|
||||
TrueNAS drive-health alerts that identify a specific disk remain disk-health
|
||||
@@ -60,7 +61,11 @@ typed uncorrectable-error or spare-reserve argument, Pulse also projects that
|
||||
value into the disk's SMART details. Pulse does not infer counters from alert
|
||||
text, and current TrueNAS APIs do not expose every raw SMART attribute.
|
||||
|
||||
Resources from TrueNAS can be filtered using the **source** filter on any page.
|
||||
The unified resource model is a backend contract, not a top-level
|
||||
Infrastructure, Storage or Recovery menu. TrueNAS tabs follow the inventory
|
||||
Pulse has collected; an absent tab is not proof of successful collection.
|
||||
For missing or stale data, use the [polling checks](#stale-truenas-data) before
|
||||
testing the connection or restarting.
|
||||
|
||||
## Multiple TrueNAS Systems
|
||||
|
||||
@@ -91,7 +96,7 @@ All endpoints require admin authentication.
|
||||
|
||||
### Testing and adding a connection (API)
|
||||
|
||||
The **Settings → TrueNAS** flow is the simplest option. For an API client,
|
||||
The **Settings → Infrastructure → Platform connections** flow is the simplest option. For an API client,
|
||||
prepare the private Pulse header file as described in the
|
||||
[API authentication guide](API.md). The Pulse API token authenticates to
|
||||
Pulse; the separate TrueNAS API key belongs in the connection's JSON file.
|
||||
@@ -260,4 +265,4 @@ Set `PULSE_ENABLE_TRUENAS=false` and restart Pulse. Existing connection data is
|
||||
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
|
||||
- [Recovery data](RECOVERY.md) — the snapshot and replication data shown under **TrueNAS → Protection**
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
// Production Docs/router/styles with the actual shipped Markdown; no backend.
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
const { chromium, webkit } = require('playwright');
|
||||
|
||||
(async () => {
|
||||
const root = '/workspace/frontend-modern';
|
||||
const artifacts = path.join(root, 'node_modules', 'navigation-help-browser');
|
||||
fs.mkdirSync(artifacts, { recursive: true });
|
||||
const { createServer } = await import(path.join(root, 'node_modules/vite/dist/node/index.js'));
|
||||
const server = await createServer({
|
||||
root,
|
||||
configFile: path.join(root, 'vite.config.ts'),
|
||||
cacheDir: path.join(root, 'node_modules', '.vite-navigation-help'),
|
||||
server: { host: '127.0.0.1', port: 5247, strictPort: true },
|
||||
optimizeDeps: { noDiscovery: true, include: [] },
|
||||
});
|
||||
const results = [];
|
||||
let browser;
|
||||
try {
|
||||
await server.listen();
|
||||
for (const [engine, width, tone] of [['chromium', 1280, 'light'], ['webkit', 390, 'dark']]) {
|
||||
browser = await { chromium, webkit }[engine].launch(
|
||||
engine === 'chromium'
|
||||
? { headless: true, channel: 'chromium', args: ['--no-sandbox'] }
|
||||
: { headless: true },
|
||||
);
|
||||
const page = await browser.newPage({
|
||||
viewport: { width, height: 900 },
|
||||
...(engine === 'webkit' ? { isMobile: true, hasTouch: true } : {}),
|
||||
});
|
||||
const errors = [];
|
||||
page.on('pageerror', (e) => errors.push(e.message));
|
||||
page.on('console', (m) => { if (m.type() === 'error') errors.push(m.text()); });
|
||||
await page.goto('http://127.0.0.1:5247/browser-tests/docs-fragment-navigation.html?scenario=troubleshooting',
|
||||
{ waitUntil: 'domcontentloaded', timeout: 60_000 });
|
||||
await page.getByRole('heading', { name: "Old bookmarks don't work", exact: true }).waitFor();
|
||||
if (tone === 'dark') await page.evaluate(() => document.documentElement.classList.add('dark'));
|
||||
const routes = page.locator('article table').filter({ hasText: '/standalone/machines' });
|
||||
assert.equal(await routes.count(), 1);
|
||||
assert.deepEqual(await routes.locator('tbody tr').allTextContents(), [
|
||||
'Proxmox/proxmox/overview', 'Docker/docker/overview', 'Kubernetes/kubernetes/overview',
|
||||
'TrueNAS/truenas/overview', 'vSphere/vmware/overview', 'Machines/standalone/machines',
|
||||
]);
|
||||
const article = await page.locator('article').innerText();
|
||||
assert.ok(article.includes('are supported; do not replace them with the retired task-based routes.'));
|
||||
assert.ok(article.includes('Do not delete connections or re-enrol agents'));
|
||||
await routes.scrollIntoViewIfNeeded();
|
||||
assert.ok(await page.evaluate(() => document.documentElement.scrollWidth <= window.innerWidth + 1));
|
||||
await page.screenshot({ path: path.join(artifacts, `${engine}-routes.png`) });
|
||||
|
||||
await page.getByRole('link', { name: 'FAQ', exact: true }).click();
|
||||
const faq = page.getByRole('heading', { name: 'How is navigation organised in Pulse v6?', exact: true });
|
||||
await faq.waitFor();
|
||||
await page.waitForFunction(() => {
|
||||
const heading = document.getElementById('how-is-navigation-organised-in-pulse-v6');
|
||||
return heading && heading.getBoundingClientRect().top >= 0 && heading.getBoundingClientRect().top < innerHeight;
|
||||
});
|
||||
assert.ok(page.url().endsWith('/docs/FAQ#how-is-navigation-organised-in-pulse-v6'));
|
||||
|
||||
await page.getByRole('link', { name: '← All documentation' }).click();
|
||||
await page.getByRole('link', { name: 'TrueNAS SCALE and CORE', exact: true }).click();
|
||||
const inventory = page.locator('article table').filter({ hasText: 'Pulse page / tab' });
|
||||
await inventory.waitFor();
|
||||
const destinations = await inventory.locator('tbody tr td:nth-child(2)').allTextContents();
|
||||
assert.deepEqual(destinations, ['TrueNAS → Overview', 'TrueNAS → VMs', 'TrueNAS → Apps',
|
||||
'TrueNAS → Storage', 'TrueNAS → Storage', 'TrueNAS → Storage',
|
||||
'TrueNAS → Protection', 'TrueNAS → Protection', 'Alerts']);
|
||||
const mapping = await page.locator('article').innerText();
|
||||
for (const route of ['/truenas/overview', '/truenas/vms', '/truenas/apps', '/truenas/storage', '/truenas/protection'])
|
||||
assert.ok(mapping.includes(route));
|
||||
await inventory.scrollIntoViewIfNeeded();
|
||||
const geometry = await inventory.evaluate((table) => ({
|
||||
localScroll: table.parentElement.dataset.docTableScroll !== undefined,
|
||||
viewport: innerWidth,
|
||||
outer: document.documentElement.scrollWidth,
|
||||
table: table.parentElement.scrollWidth,
|
||||
wrapper: table.parentElement.clientWidth,
|
||||
}));
|
||||
assert.ok(geometry.localScroll);
|
||||
assert.ok(geometry.outer <= geometry.viewport + 1);
|
||||
if (width === 390) assert.ok(geometry.table > geometry.wrapper);
|
||||
await page.screenshot({ path: path.join(artifacts, `${engine}-truenas.png`) });
|
||||
|
||||
await page.getByRole('link', { name: '← All documentation' }).click();
|
||||
await page.getByRole('link', { name: 'Proxmox Backup Server', exact: true }).click();
|
||||
const pbs = page.getByRole('heading', { name: 'Data Source Indicator', exact: true });
|
||||
await pbs.waitFor();
|
||||
const pbsText = await page.locator('article').innerText();
|
||||
assert.ok(pbsText.includes('Proxmox → Backups (/proxmox/backups)'));
|
||||
assert.ok(pbsText.includes('There is no current top-level Recovery page'));
|
||||
await pbs.scrollIntoViewIfNeeded();
|
||||
assert.ok(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth + 1));
|
||||
await page.screenshot({ path: path.join(artifacts, `${engine}-pbs.png`) });
|
||||
assert.deepEqual(errors, []);
|
||||
results.push({ engine, version: browser.version(), width, tone, routes: 6, destinations,
|
||||
geometry, faqFragment: true, pbsPlacement: true, errors });
|
||||
await browser.close();
|
||||
browser = undefined;
|
||||
}
|
||||
const result = { result: 'passed', playwright: require('playwright/package.json').version,
|
||||
scope: 'shipped help rendering and navigation, not appliance collection', results };
|
||||
fs.writeFileSync(path.join(artifacts, 'result.json'), JSON.stringify(result, null, 2) + '\n');
|
||||
console.log(JSON.stringify(result));
|
||||
} finally {
|
||||
if (browser) await browser.close();
|
||||
await server.close();
|
||||
}
|
||||
})().catch((error) => { console.error(error); process.exitCode = 1; });
|
||||
@@ -152,7 +152,7 @@ It does **not** allow:
|
||||
|
||||
If you have multiple PBS servers, add each one separately in Settings. Pulse will:
|
||||
- Monitor each server independently
|
||||
- Show backups from all servers in the unified Recovery view
|
||||
- Show backups from all servers under **Proxmox → Backups** (`/proxmox/backups`)
|
||||
- Deduplicate if the same backup appears via both PVE passthrough and direct PBS
|
||||
|
||||
---
|
||||
@@ -301,7 +301,8 @@ or change retention to hide a display problem.
|
||||
|
||||
## Data Source Indicator
|
||||
|
||||
In the Recovery view, PBS backups show a data source indicator:
|
||||
Under **Proxmox → Backups** (`/proxmox/backups`), PBS backups show a data source
|
||||
indicator. There is no current top-level Recovery page:
|
||||
|
||||
- **"PBS"** badge alone = Direct PBS connection (full data)
|
||||
- **"PBS via PVE"** = Passthrough via PVE storage (limited data)
|
||||
|
||||
@@ -413,7 +413,7 @@ consequential, manually redacted error.
|
||||
### TrueNAS
|
||||
|
||||
#### "TrueNAS service unavailable"
|
||||
- Ensure TrueNAS was added in **Settings → TrueNAS** with a valid HTTPS URL,
|
||||
- Ensure TrueNAS was added in **Settings → Infrastructure → Platform connections** 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).
|
||||
@@ -424,7 +424,10 @@ consequential, manually redacted error.
|
||||
#### TrueNAS pools/datasets not appearing
|
||||
- TrueNAS data appears in the unified resource model and may take one configured
|
||||
polling cycle (60 seconds by default) to appear.
|
||||
- Check **Infrastructure** (TrueNAS host), **Storage** (pools/datasets), and **Recovery** (snapshots/replication).
|
||||
- Open **TrueNAS → Overview** for the appliance, **TrueNAS → Storage**
|
||||
(`/truenas/storage`) for pools, datasets and disks, and **TrueNAS → Protection**
|
||||
(`/truenas/protection`) for snapshots and replication. These are tabs within
|
||||
TrueNAS, not separate top-level Storage or Recovery pages.
|
||||
- For data that stops refreshing, use the [TrueNAS polling checks](TRUENAS.md#stale-truenas-data)
|
||||
before testing or restarting. A stale badge is not proof of an invalid key,
|
||||
and a successful connection test is not proof that collection has recovered.
|
||||
@@ -432,8 +435,38 @@ consequential, manually redacted error.
|
||||
### Navigation (v6)
|
||||
|
||||
#### Old bookmarks don't work
|
||||
- Legacy URLs (`/proxmox`, `/docker`, `/kubernetes`, `/hosts`, `/services`) are not supported in v6.
|
||||
- Update bookmarks to canonical routes. See [Migration Guide](MIGRATION_UNIFIED_NAV.md).
|
||||
|
||||
Current Pulse uses platform navigation. `/proxmox`, `/docker` and `/kubernetes`
|
||||
are supported; do not replace them with the retired task-based routes.
|
||||
Open Pulse at its base URL and use the menu to find the relevant page:
|
||||
|
||||
| Menu | Entry route |
|
||||
| --- | --- |
|
||||
| Proxmox | `/proxmox/overview` |
|
||||
| Docker | `/docker/overview` |
|
||||
| Kubernetes | `/kubernetes/overview` |
|
||||
| TrueNAS | `/truenas/overview` |
|
||||
| vSphere | `/vmware/overview` |
|
||||
| Machines | `/standalone/machines` |
|
||||
|
||||
The short-lived top-level `/workloads`, `/storage` and `/recovery` layout is
|
||||
retired. `/infrastructure` now opens the default workspace, not the former
|
||||
unified host page. For old `/hosts` or `/services` bookmarks, select the current
|
||||
platform or Machines page instead of assuming an automatic redirect. PBS
|
||||
backups are under **Proxmox → Backups**, and TrueNAS snapshots and replication
|
||||
are under **TrueNAS → Protection**.
|
||||
|
||||
Platform-connected hosts can appear under their platform rather than Machines.
|
||||
If a menu or expected resource is missing, check its saved connection and last
|
||||
successful collection in **Settings → Infrastructure**; a missing page alone
|
||||
does not prove a host was deleted. Do not delete connections or re-enrol agents
|
||||
just to repair a bookmark.
|
||||
|
||||
If menu navigation works but reloading the same URL returns a proxy 404, check
|
||||
the proxy's route handling using [Reverse Proxy Configuration](REVERSE_PROXY.md).
|
||||
For the current layout, see [FAQ](FAQ.md#how-is-navigation-organised-in-pulse-v6).
|
||||
The [unified-navigation migration](MIGRATION_UNIFIED_NAV.md) is historical,
|
||||
not a guide to the current menu.
|
||||
|
||||
### Relay / Mobile
|
||||
|
||||
|
||||
@@ -4,8 +4,9 @@ Pulse v6 includes first-class monitoring for **TrueNAS SCALE** and **TrueNAS COR
|
||||
|
||||
## Quick Start
|
||||
|
||||
1. Go to **Settings → TrueNAS**.
|
||||
2. Click **Add Connection**.
|
||||
1. Go to **Settings → Infrastructure**.
|
||||
2. Click **Add infrastructure** and choose **TrueNAS**. Existing connections
|
||||
are listed under **Platform connections**.
|
||||
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**.
|
||||
@@ -28,27 +29,27 @@ On your TrueNAS system:
|
||||
|
||||
## What Gets Monitored
|
||||
|
||||
| Data | Unified Page | Details |
|
||||
| Data | Pulse page / tab | Details |
|
||||
|---|---|---|
|
||||
| System info (hostname, version, uptime) | Infrastructure | CPU, memory, health status |
|
||||
| Virtual machines | TrueNAS Overview | State, CPU, memory, boot mode, devices, and security flags from the TrueNAS VM API |
|
||||
| Apps | TrueNAS Overview | Native app state, image/version, ports, volumes, networks, and runtime container details |
|
||||
| ZFS Pools | Storage | Total/used/free capacity, pool status (ONLINE/DEGRADED/FAULTED) |
|
||||
| ZFS Datasets | Storage | Used/available space, mount status, read-only flag |
|
||||
| Physical Disks | Storage | Model, serial, size, transport type, rotational flag, temperature, and native SMART failure/counter evidence when TrueNAS reports it |
|
||||
| ZFS Snapshots | Recovery | Dataset, creation time, size, referenced data |
|
||||
| Replication Tasks | Recovery | Source/target datasets, direction, last run status |
|
||||
| System info (hostname, version, uptime) | TrueNAS → Overview | CPU, memory, health status |
|
||||
| Virtual machines | TrueNAS → VMs | State, CPU, memory, boot mode, devices, and security flags from the TrueNAS VM API |
|
||||
| Apps | TrueNAS → Apps | Native app state, image/version, ports, volumes, networks, and runtime container details |
|
||||
| ZFS Pools | TrueNAS → Storage | Total/used/free capacity, pool status (ONLINE/DEGRADED/FAULTED) |
|
||||
| ZFS Datasets | TrueNAS → Storage | Used/available space, mount status, read-only flag |
|
||||
| Physical Disks | TrueNAS → Storage | Model, serial, size, transport type, rotational flag, temperature, and native SMART failure/counter evidence when TrueNAS reports it |
|
||||
| ZFS Snapshots | TrueNAS → Protection | Dataset, creation time, size, referenced data |
|
||||
| Replication Tasks | TrueNAS → Protection | Source/target datasets, direction, last run status |
|
||||
| TrueNAS Alerts | Alerts | Native TrueNAS alert messages and severity levels |
|
||||
|
||||
## Unified Resource Mapping
|
||||
|
||||
TrueNAS resources are mapped into the unified resource model:
|
||||
|
||||
- **TrueNAS host** → appears as a resource with `source: truenas` on the **Infrastructure** page.
|
||||
- **TrueNAS VMs** → appear as canonical `vm` workloads on the **TrueNAS** page.
|
||||
- **TrueNAS apps** → appear as canonical `app-container` workloads on the **TrueNAS** page.
|
||||
- **ZFS pools and datasets** → appear on the **Storage** page.
|
||||
- **ZFS snapshots and replication** → appear on the **Recovery** page as recovery points.
|
||||
- **TrueNAS host** → appears as a resource with `source: truenas` under **TrueNAS → Overview** (`/truenas/overview`).
|
||||
- **TrueNAS VMs** → appear as canonical `vm` workloads under **TrueNAS → VMs** (`/truenas/vms`).
|
||||
- **TrueNAS apps** → appear as canonical `app-container` workloads under **TrueNAS → Apps** (`/truenas/apps`).
|
||||
- **ZFS pools, datasets and physical disks** → appear under **TrueNAS → Storage** (`/truenas/storage`).
|
||||
- **ZFS snapshots and replication** → appear under **TrueNAS → Protection** (`/truenas/protection`) as recovery points.
|
||||
- **TrueNAS alerts** → surfaced on the **Alerts** page alongside Proxmox and other platform alerts.
|
||||
|
||||
TrueNAS drive-health alerts that identify a specific disk remain disk-health
|
||||
@@ -60,7 +61,11 @@ typed uncorrectable-error or spare-reserve argument, Pulse also projects that
|
||||
value into the disk's SMART details. Pulse does not infer counters from alert
|
||||
text, and current TrueNAS APIs do not expose every raw SMART attribute.
|
||||
|
||||
Resources from TrueNAS can be filtered using the **source** filter on any page.
|
||||
The unified resource model is a backend contract, not a top-level
|
||||
Infrastructure, Storage or Recovery menu. TrueNAS tabs follow the inventory
|
||||
Pulse has collected; an absent tab is not proof of successful collection.
|
||||
For missing or stale data, use the [polling checks](#stale-truenas-data) before
|
||||
testing the connection or restarting.
|
||||
|
||||
## Multiple TrueNAS Systems
|
||||
|
||||
@@ -91,7 +96,7 @@ All endpoints require admin authentication.
|
||||
|
||||
### Testing and adding a connection (API)
|
||||
|
||||
The **Settings → TrueNAS** flow is the simplest option. For an API client,
|
||||
The **Settings → Infrastructure → Platform connections** flow is the simplest option. For an API client,
|
||||
prepare the private Pulse header file as described in the
|
||||
[API authentication guide](API.md). The Pulse API token authenticates to
|
||||
Pulse; the separate TrueNAS API key belongs in the connection's JSON file.
|
||||
@@ -260,4 +265,4 @@ Set `PULSE_ENABLE_TRUENAS=false` and restart Pulse. Existing connection data is
|
||||
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
|
||||
- [Recovery data](RECOVERY.md) — the snapshot and replication data shown under **TrueNAS → Protection**
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Keep operator navigation guidance tied to the shipped routes and tab labels.
|
||||
|
||||
These checks cover documentation accuracy, not collection or appliance health.
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
import re
|
||||
import unittest
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
|
||||
|
||||
def doc_text(name: str) -> str:
|
||||
return (ROOT / "docs" / name).read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def source(name: str) -> str:
|
||||
return (ROOT / "frontend-modern/src" / name).read_text(encoding="utf-8")
|
||||
|
||||
|
||||
class NavigationHelpDocsTest(unittest.TestCase):
|
||||
def test_entry_routes_match_the_registered_platform_routes(self):
|
||||
guide = doc_text("TROUBLESHOOTING.md").split("#### Old bookmarks don't work", 1)[1]
|
||||
guide = guide.split("### Relay / Mobile", 1)[0]
|
||||
links = source("routing/resourceLinks.ts")
|
||||
app = source("App.tsx")
|
||||
for label, prefix in (("Proxmox", "PROXMOX"), ("Docker", "DOCKER"),
|
||||
("Kubernetes", "KUBERNETES"), ("TrueNAS", "TRUENAS"),
|
||||
("vSphere", "VMWARE"), ("Machines", "STANDALONE")):
|
||||
with self.subTest(platform=label):
|
||||
path = re.search(rf"export const {prefix}_PATH = '([^']+)';", links).group(1)
|
||||
tab = re.search(rf"export const {prefix}_DEFAULT_TAB = '([^']+)';", links).group(1)
|
||||
self.assertIn(f"| {label} | `{path}/{tab}` |", guide)
|
||||
self.assertIn(f'<Route path={{{prefix}_PATH}}', app)
|
||||
self.assertNotIn("Legacy URLs", guide)
|
||||
self.assertIn("are supported", guide)
|
||||
|
||||
def test_navigation_guidance_preserves_connections_and_separates_proxy_failures(self):
|
||||
guide = doc_text("TROUBLESHOOTING.md")
|
||||
for phrase in ("rather than Machines", "last\nsuccessful collection",
|
||||
"Do not delete connections or re-enrol agents",
|
||||
"reloading the same URL returns a proxy 404",
|
||||
"REVERSE_PROXY.md", "FAQ.md#how-is-navigation-organised-in-pulse-v6",
|
||||
"is historical,\nnot a guide to the current menu"):
|
||||
with self.subTest(phrase=phrase):
|
||||
self.assertIn(phrase, guide)
|
||||
# /infrastructure is still an entry route, not an invented missing page.
|
||||
self.assertIn('<Route path="/infrastructure" component={RuntimeHomePage}', source("App.tsx"))
|
||||
self.assertIn("`/infrastructure` now opens the default workspace", guide)
|
||||
|
||||
def test_truenas_locations_match_the_actual_tab_labels_and_paths(self):
|
||||
model = source("features/truenas/truenasPageModel.ts")
|
||||
tabs = dict(re.findall(r"label: '([^']+)', path: '(/truenas/[^']+)'", model))
|
||||
guide = doc_text("TRUENAS.md")
|
||||
for label in ("Overview", "Storage", "Protection", "Apps", "VMs"):
|
||||
with self.subTest(tab=label):
|
||||
self.assertIn(f"**TrueNAS → {label}** (`{tabs[label]}`)", guide)
|
||||
self.assertIn(f"| TrueNAS → {label} |", guide)
|
||||
self.assertNotIn("| Unified Page |", guide)
|
||||
self.assertNotIn("on the **Infrastructure** page", guide)
|
||||
self.assertNotIn("on the **Recovery** page", guide)
|
||||
self.assertNotIn("on the **Storage** page", guide)
|
||||
|
||||
def test_general_truenas_help_uses_platform_tabs(self):
|
||||
guide = doc_text("TROUBLESHOOTING.md").split("### TrueNAS", 1)[1].split("### Navigation", 1)[0]
|
||||
for label in ("Overview", "Storage", "Protection"):
|
||||
self.assertIn(f"**TrueNAS → {label}**", guide)
|
||||
for path in ("/truenas/storage", "/truenas/protection"):
|
||||
self.assertIn(f"`{path}`", guide)
|
||||
self.assertIn("TRUENAS.md#stale-truenas-data", guide)
|
||||
|
||||
def test_setup_uses_the_existing_infrastructure_editor(self):
|
||||
guide = doc_text("TRUENAS.md")
|
||||
self.assertIn("**Settings → Infrastructure**", guide)
|
||||
self.assertIn("**Add infrastructure** and choose **TrueNAS**", guide)
|
||||
self.assertNotIn("**Settings → TrueNAS**", guide)
|
||||
editor = source("components/Settings/InfrastructureWorkspace.tsx")
|
||||
self.assertIn("return 'Add infrastructure'", editor)
|
||||
self.assertIn("case 'truenas':", editor)
|
||||
self.assertIn("<TrueNASCredentialSlot", editor)
|
||||
|
||||
def test_pbs_backups_live_under_proxmox_not_top_level_recovery(self):
|
||||
guide = doc_text("PBS.md")
|
||||
self.assertGreaterEqual(guide.count("**Proxmox → Backups** (`/proxmox/backups`)"), 2)
|
||||
self.assertNotIn("unified Recovery view", guide)
|
||||
self.assertNotIn("In the Recovery view", guide)
|
||||
self.assertIn("{ id: 'backups', label: 'Backups'", source("features/proxmox/proxmoxPageModel.ts"))
|
||||
self.assertIn("PROXMOX_BACKUPS_PATH = `${PROXMOX_PATH}/backups`", source("routing/resourceLinks.ts"))
|
||||
|
||||
def test_all_changed_guides_match_their_shipped_copies(self):
|
||||
for name in ("TROUBLESHOOTING.md", "TRUENAS.md", "PBS.md"):
|
||||
with self.subTest(guide=name):
|
||||
self.assertEqual(doc_text(name),
|
||||
(ROOT / "frontend-modern/public/docs" / name).read_text(encoding="utf-8"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user