rigscope 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/BUILD_ID +1 -0
- package/.next/app-path-routes-manifest.json +13 -0
- package/.next/build-manifest.json +20 -0
- package/.next/export-marker.json +6 -0
- package/.next/images-manifest.json +68 -0
- package/.next/next-minimal-server.js.nft.json +1 -0
- package/.next/next-server.js.nft.json +1 -0
- package/.next/package.json +1 -0
- package/.next/prerender-manifest.json +297 -0
- package/.next/react-loadable-manifest.json +1 -0
- package/.next/required-server-files.json +369 -0
- package/.next/routes-manifest.json +114 -0
- package/.next/server/app/_global-error/page.js +31 -0
- package/.next/server/app/_global-error/page.js.nft.json +1 -0
- package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -0
- package/.next/server/app/_global-error.html +1 -0
- package/.next/server/app/_global-error.meta +35 -0
- package/.next/server/app/_global-error.rsc +18 -0
- package/.next/server/app/_global-error.segments/_full.segment.rsc +18 -0
- package/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +24 -0
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +3 -0
- package/.next/server/app/_not-found/page.js +1 -0
- package/.next/server/app/_not-found/page.js.nft.json +1 -0
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -0
- package/.next/server/app/_not-found.html +1 -0
- package/.next/server/app/_not-found.meta +35 -0
- package/.next/server/app/_not-found.rsc +24 -0
- package/.next/server/app/_not-found.segments/_full.segment.rsc +24 -0
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +30 -0
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +4 -0
- package/.next/server/app/administration/page.js +1 -0
- package/.next/server/app/administration/page.js.nft.json +1 -0
- package/.next/server/app/administration/page_client-reference-manifest.js +1 -0
- package/.next/server/app/administration.html +1 -0
- package/.next/server/app/administration.meta +34 -0
- package/.next/server/app/administration.rsc +29 -0
- package/.next/server/app/administration.segments/_full.segment.rsc +29 -0
- package/.next/server/app/administration.segments/_tree.segment.rsc +4 -0
- package/.next/server/app/administration.segments/administration/__PAGE__.segment.rsc +35 -0
- package/.next/server/app/alerts/page.js +1 -0
- package/.next/server/app/alerts/page.js.nft.json +1 -0
- package/.next/server/app/alerts/page_client-reference-manifest.js +1 -0
- package/.next/server/app/alerts.html +1 -0
- package/.next/server/app/alerts.meta +34 -0
- package/.next/server/app/alerts.rsc +28 -0
- package/.next/server/app/alerts.segments/_full.segment.rsc +28 -0
- package/.next/server/app/alerts.segments/_tree.segment.rsc +4 -0
- package/.next/server/app/alerts.segments/alerts/__PAGE__.segment.rsc +34 -0
- package/.next/server/app/connections/page.js +1 -0
- package/.next/server/app/connections/page.js.nft.json +1 -0
- package/.next/server/app/connections/page_client-reference-manifest.js +1 -0
- package/.next/server/app/connections.html +1 -0
- package/.next/server/app/connections.meta +34 -0
- package/.next/server/app/connections.rsc +29 -0
- package/.next/server/app/connections.segments/_full.segment.rsc +29 -0
- package/.next/server/app/connections.segments/_tree.segment.rsc +4 -0
- package/.next/server/app/connections.segments/connections/__PAGE__.segment.rsc +35 -0
- package/.next/server/app/history/page.js +2 -0
- package/.next/server/app/history/page.js.nft.json +1 -0
- package/.next/server/app/history/page_client-reference-manifest.js +1 -0
- package/.next/server/app/history.html +1 -0
- package/.next/server/app/history.meta +34 -0
- package/.next/server/app/history.rsc +33 -0
- package/.next/server/app/history.segments/_full.segment.rsc +33 -0
- package/.next/server/app/history.segments/_tree.segment.rsc +4 -0
- package/.next/server/app/history.segments/history/__PAGE__.segment.rsc +37 -0
- package/.next/server/app/icon.svg/route.js +1 -0
- package/.next/server/app/icon.svg/route.js.nft.json +1 -0
- package/.next/server/app/icon.svg.body +1 -0
- package/.next/server/app/icon.svg.meta +1 -0
- package/.next/server/app/index.html +1 -0
- package/.next/server/app/index.meta +29 -0
- package/.next/server/app/index.rsc +26 -0
- package/.next/server/app/index.segments/__PAGE__.segment.rsc +31 -0
- package/.next/server/app/index.segments/_full.segment.rsc +26 -0
- package/.next/server/app/index.segments/_tree.segment.rsc +3 -0
- package/.next/server/app/login/page.js +1 -0
- package/.next/server/app/login/page.js.nft.json +1 -0
- package/.next/server/app/login/page_client-reference-manifest.js +1 -0
- package/.next/server/app/login.html +1 -0
- package/.next/server/app/login.meta +34 -0
- package/.next/server/app/login.rsc +26 -0
- package/.next/server/app/login.segments/_full.segment.rsc +26 -0
- package/.next/server/app/login.segments/_tree.segment.rsc +4 -0
- package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +32 -0
- package/.next/server/app/machines/[machineId]/page.js +1 -0
- package/.next/server/app/machines/[machineId]/page.js.nft.json +1 -0
- package/.next/server/app/machines/[machineId]/page_client-reference-manifest.js +1 -0
- package/.next/server/app/page.js +1 -0
- package/.next/server/app/page.js.nft.json +1 -0
- package/.next/server/app/page_client-reference-manifest.js +1 -0
- package/.next/server/app/processes/page.js +2 -0
- package/.next/server/app/processes/page.js.nft.json +1 -0
- package/.next/server/app/processes/page_client-reference-manifest.js +1 -0
- package/.next/server/app/processes.html +1 -0
- package/.next/server/app/processes.meta +34 -0
- package/.next/server/app/processes.rsc +30 -0
- package/.next/server/app/processes.segments/_full.segment.rsc +30 -0
- package/.next/server/app/processes.segments/_tree.segment.rsc +4 -0
- package/.next/server/app/processes.segments/processes/__PAGE__.segment.rsc +36 -0
- package/.next/server/app-paths-manifest.json +13 -0
- package/.next/server/chunks/161.js +1 -0
- package/.next/server/chunks/168.js +1 -0
- package/.next/server/chunks/266.js +68 -0
- package/.next/server/chunks/430.js +116 -0
- package/.next/server/chunks/721.js +1 -0
- package/.next/server/chunks/751.js +1 -0
- package/.next/server/chunks/877.js +1 -0
- package/.next/server/chunks/894.js +2 -0
- package/.next/server/functions-config-manifest.json +4 -0
- package/.next/server/interception-route-rewrite-manifest.js +1 -0
- package/.next/server/middleware-build-manifest.js +1 -0
- package/.next/server/middleware-manifest.json +6 -0
- package/.next/server/middleware-react-loadable-manifest.js +1 -0
- package/.next/server/next-font-manifest.js +1 -0
- package/.next/server/next-font-manifest.json +1 -0
- package/.next/server/pages/404.html +1 -0
- package/.next/server/pages/500.html +1 -0
- package/.next/server/pages-manifest.json +4 -0
- package/.next/server/prefetch-hints.json +123 -0
- package/.next/server/preview-props.json +5 -0
- package/.next/server/server-reference-manifest.js +1 -0
- package/.next/server/server-reference-manifest.json +1 -0
- package/.next/server/webpack-runtime.js +1 -0
- package/.next/static/DZKWF9ur7H5wI0c7RAhdq/_buildManifest.js +1 -0
- package/.next/static/DZKWF9ur7H5wI0c7RAhdq/_ssgManifest.js +1 -0
- package/.next/static/chunks/103-c47318242b24e9ac.js +1 -0
- package/.next/static/chunks/157-0d36ebf66af048ac.js +1 -0
- package/.next/static/chunks/227-417939c480f50747.js +1 -0
- package/.next/static/chunks/408-18819c6490a5f8d3.js +1 -0
- package/.next/static/chunks/4bd1b696-c7408084347438ae.js +1 -0
- package/.next/static/chunks/794-ceeb732a1a81bc27.js +52 -0
- package/.next/static/chunks/939-2600d7c8e583d5ef.js +1 -0
- package/.next/static/chunks/app/_global-error/page-aba28f88d5781771.js +1 -0
- package/.next/static/chunks/app/_not-found/page-a2a510233e4836e2.js +1 -0
- package/.next/static/chunks/app/administration/page-4b16b19bb6a39c36.js +1 -0
- package/.next/static/chunks/app/alerts/page-fe0e877778c60af8.js +1 -0
- package/.next/static/chunks/app/connections/page-99cd54d6929b3f1f.js +1 -0
- package/.next/static/chunks/app/history/page-3fa5846eca26b7f7.js +3 -0
- package/.next/static/chunks/app/layout-4feff677c4071745.js +1 -0
- package/.next/static/chunks/app/login/page-c57e12dbe5146737.js +1 -0
- package/.next/static/chunks/app/machines/[machineId]/page-a5aa1d8676272f38.js +1 -0
- package/.next/static/chunks/app/page-1ae9fc94c897785b.js +1 -0
- package/.next/static/chunks/app/processes/page-e471ed23a1d5632f.js +3 -0
- package/.next/static/chunks/framework-ea4f97ca039bd777.js +1 -0
- package/.next/static/chunks/main-a458d32948147b84.js +5 -0
- package/.next/static/chunks/main-app-f92328c8950d2e53.js +1 -0
- package/.next/static/chunks/next/dist/client/components/builtin/app-error-aba28f88d5781771.js +1 -0
- package/.next/static/chunks/next/dist/client/components/builtin/forbidden-aba28f88d5781771.js +1 -0
- package/.next/static/chunks/next/dist/client/components/builtin/global-error-43cbaa3aa1576eb4.js +1 -0
- package/.next/static/chunks/next/dist/client/components/builtin/not-found-aba28f88d5781771.js +1 -0
- package/.next/static/chunks/next/dist/client/components/builtin/unauthorized-aba28f88d5781771.js +1 -0
- package/.next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
- package/.next/static/chunks/webpack-9ca43f4ce1bb8938.js +1 -0
- package/.next/static/css/e41ccbccc3afaae5.css +1 -0
- package/ARCHITECTURE.md +279 -0
- package/CHANGELOG.md +25 -0
- package/DESIGN.md +299 -0
- package/LICENSE +21 -0
- package/README.md +157 -2
- package/SECURITY.md +12 -0
- package/THIRD_PARTY_NOTICES.md +8847 -0
- package/bin/rigscope.cjs +6 -0
- package/dist/cli.cjs +9075 -0
- package/dist/collector.cjs +5671 -0
- package/dist/hub.cjs +8355 -0
- package/dist/ops.cjs +4972 -0
- package/dist/system.cjs +4333 -0
- package/docs/bottlenecks.md +62 -0
- package/docs/development.md +46 -0
- package/docs/exports.md +39 -0
- package/docs/installation.md +477 -0
- package/docs/operations.md +515 -0
- package/docs/releasing.md +152 -0
- package/docs/scale-acceptance.json +412 -0
- package/docs/scale-validation.json +1898 -0
- package/docs/scale-validation.md +263 -0
- package/next.config.js +38 -0
- package/package.json +109 -4
- package/packaging/README.md +5 -0
- package/packaging/collector.env.example +24 -0
- package/packaging/hub.env.example +31 -0
- package/packaging/system/90-rigscope-rapl.rules +7 -0
- package/packaging/system/README.md +5 -0
- package/packaging/system/rigscope-collector.service.example +53 -0
- package/packaging/system/rigscope-hub.service.example +50 -0
- package/packaging/system/rigscope-rapl.sysusers +5 -0
- package/packaging/system/rigscope.sysusers +7 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Bottleneck telemetry
|
|
2
|
+
|
|
3
|
+
Overview shows available bottleneck readings alongside existing resource panels.
|
|
4
|
+
History records the same readings and offers separate charts for units such as
|
|
5
|
+
temperature, watts and milliseconds. Select **CPU cores** in History to compare cores; the selection is saved per machine and applies to exports. Up to eight series use lines; larger selections use a scrollable heatmap. Drawing groups
|
|
6
|
+
points toward a 150-point target per core while preserving extrema and gaps;
|
|
7
|
+
downloads retain the loaded stored buckets rather than the drawing reduction.
|
|
8
|
+
|
|
9
|
+
Readings are optional. An older collector, missing kernel interface, unreadable
|
|
10
|
+
file or reset counter produces an unavailable reading rather than zero. GPU
|
|
11
|
+
power and CPU package power are separate measurements; neither is whole-machine
|
|
12
|
+
wall power.
|
|
13
|
+
|
|
14
|
+
| Reading | Source and meaning |
|
|
15
|
+
| --- | --- |
|
|
16
|
+
| CPU temperature | Readable CPU hwmon sensors; package/Tctl/Tdie sensors take precedence over core sensors. Reports the hottest reading in the preferred class. |
|
|
17
|
+
| CPU package power | Change in top-level RAPL package energy over monotonic elapsed time, summed across readable packages. Package subdomains are excluded. Requires two valid observations. |
|
|
18
|
+
| CPU I/O wait | Change in procfs CPU iowait ticks, normalized by elapsed time and logical core count. |
|
|
19
|
+
| CPU pressure | Linux PSI `some avg10`: percentage of time with tasks stalled for CPU over the recent ten-second window. |
|
|
20
|
+
| Memory / I/O pressure | PSI `some avg10` and `full avg10`; `full` measures simultaneous stalls of all non-idle tasks. |
|
|
21
|
+
| Disk read / write latency | Change in diskstats operation milliseconds divided by completed operations. No completed operations means unavailable latency. |
|
|
22
|
+
| Disk utilization | Change in diskstats I/O-active milliseconds divided by elapsed time, capped at 100%. This is not a throughput-capacity estimate for parallel devices. |
|
|
23
|
+
| Filesystem inode use | Used inode count divided by a positive total from `statfs`. Filesystems without usable inode totals remain unavailable. |
|
|
24
|
+
| Memory / filesystem use | Used bytes divided by a positive total, on the 0–100 percent scale. |
|
|
25
|
+
|
|
26
|
+
CPU temperature supports known CPU hwmon drivers, including `coretemp` and
|
|
27
|
+
`k10temp`. CPU package power uses the Linux powercap `intel-rapl:N` interface,
|
|
28
|
+
including compatible AMD implementations. Many systems restrict `energy_uj` to
|
|
29
|
+
root. The collector remains unprivileged. The optional
|
|
30
|
+
[system installer](installation.md#system-installation) grants its dedicated account persistent
|
|
31
|
+
read-only package-counter access; ordinary user installation leaves permissions
|
|
32
|
+
under the operator's control.
|
|
33
|
+
|
|
34
|
+
Counter resets invalidate the affected derived reading until a valid interval is
|
|
35
|
+
available. RAPL wrap handling requires a readable energy range and a previous
|
|
36
|
+
counter near its ceiling. Monitoring continues when an optional sensor fails.
|
|
37
|
+
|
|
38
|
+
The new fields belong to the existing CPU, memory and disks sharing families.
|
|
39
|
+
Withholding a family withholds its bottleneck fields for that destination too.
|
|
40
|
+
|
|
41
|
+
Enhanced fields are negotiated independently for each hub. Upgraded collectors
|
|
42
|
+
advertise wire revision `0.3.0`; upgraded hubs opt in with `bottleneck-v1` in their
|
|
43
|
+
welcome. Older hubs receive the original metric shape, including replay. Older
|
|
44
|
+
collectors receive the original welcome shape. Upgrade the hub and collector to
|
|
45
|
+
see enhanced readings; an independent older destination continues receiving its
|
|
46
|
+
existing metrics. Projection affects transmission, not the durable outbox record.
|
|
47
|
+
|
|
48
|
+
Kernel references: [PSI](https://docs.kernel.org/accounting/psi.html),
|
|
49
|
+
[powercap](https://docs.kernel.org/power/powercap/powercap.html), and
|
|
50
|
+
[disk statistics](https://docs.kernel.org/admin-guide/iostats.html).
|
|
51
|
+
|
|
52
|
+
## Warning presets
|
|
53
|
+
|
|
54
|
+
In Alerts, choose a preset while creating a rule. The preset fills editable
|
|
55
|
+
fields; **Create rule** is still required. Presets include high CPU, memory or
|
|
56
|
+
disk nearly full, inode use, hot CPU/GPU, offline collectors, pressure stalls,
|
|
57
|
+
I/O wait and disk latency/utilization. Resource presets use the selected machine's
|
|
58
|
+
inventory, preferring its root filesystem when available.
|
|
59
|
+
|
|
60
|
+
Percentage thresholds use 0–100. Preset thresholds and durations are starting
|
|
61
|
+
points to review for the workload and hardware, not manufacturer safety limits.
|
|
62
|
+
Unavailable readings/resources are identified before applying a preset.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Development
|
|
2
|
+
|
|
3
|
+
Use Node.js 26+ and Linux for real collection. Keep private configuration outside Git, with directories 0700 and files 0600. Public fixture credentials are only for isolated tests.
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
npm ci
|
|
7
|
+
npm run dev
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
Development uses `.next-dev`; production uses `.next`. Configure users and collector credentials privately before starting a hub. With no browser users it fails closed. Do not run two hubs against the same database or build output.
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
npm run build
|
|
14
|
+
npm start
|
|
15
|
+
# After enrollment, in a separate terminal or service:
|
|
16
|
+
npm run collector:start
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
`npm run collector:enroll` uses `COLLECTOR_ENROLL_URL` and a private `COLLECTOR_ENROLL_TOKEN`. `npm run collector:mock` emits synthetic readings. Real collection continues without a browser. See the README for configuration and destination sharing policy.
|
|
20
|
+
|
|
21
|
+
## HTTPS boundary
|
|
22
|
+
|
|
23
|
+
Local HTTP is literal loopback only. Remote access requires `HUB_PUBLIC_ORIGIN` and `HUB_SOCKET_PATH` together: an exact HTTPS origin and an absolute Unix socket inside a private directory. The TLS reverse proxy must support WebSocket upgrades, unbuffered SSE, the configured Host and long-lived connections. The remote-mode hub has no TCP listener. The CLI does not configure DNS, certificates, Tailscale or a proxy.
|
|
24
|
+
|
|
25
|
+
Cookies are Secure and HttpOnly remotely; same-origin validation and machine scope apply to queries, streams and mutations. A hub restart invalidates in-memory sessions. Development HMR upgrades must reach Next.js while collector upgrades reach `/api/collector/connect`. Browser sign-in during development reconnects to the authenticated socket.
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
curl --fail --silent --unix-socket /path/private/hub.sock \
|
|
29
|
+
-H 'Host: monitor.example.invalid' http://localhost/api/health
|
|
30
|
+
npm run validate:https
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The validation command checks an already configured endpoint. Supply its `RIGSCOPE_VALIDATE_*` settings privately; inspect `scripts/validate-https.cjs` for the exact inputs. It does not deploy or change credentials. Health checks and anonymous rejection alone do not prove an authenticated owner stream advances or reconnects.
|
|
34
|
+
|
|
35
|
+
## Targeted verification
|
|
36
|
+
|
|
37
|
+
| Command | Scope / default workers |
|
|
38
|
+
| --- | --- |
|
|
39
|
+
| `npm test` | Source tests; 4 concurrent files, `RIGSCOPE_TEST_CONCURRENCY` |
|
|
40
|
+
| `npm run test:runtime` | Packaged runtime topology/auth/durability; 4 concurrent files, `RIGSCOPE_RUNTIME_TEST_CONCURRENCY` |
|
|
41
|
+
| `npm run test:dev` | Development/HMR integration; 1 file at a time, `RIGSCOPE_DEV_TEST_CONCURRENCY` |
|
|
42
|
+
| `npm run build:ui` | Production UI and TypeScript; `RIGSCOPE_BUILD_WORKERS`, default `min(4, available CPUs)` |
|
|
43
|
+
| `npm run build:runtime` | Hub, collector, CLI and operations bundles |
|
|
44
|
+
| `npm run typecheck` | Repository TypeScript check |
|
|
45
|
+
|
|
46
|
+
Run the narrow checks relevant to the change. Build the UI once before runtime integration tests that require it; avoid duplicate unchanged builds. Tests use isolated state and never authorize touching host services or private installed data. `RIGSCOPE_REAL_HW=1 npx tsx --test tests/sampling-real.test.ts` explicitly opts into host collection. See [releasing](releasing.md) for package validation and evidence boundaries.
|
package/docs/exports.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Export monitoring data
|
|
2
|
+
|
|
3
|
+
History and Processes provide CSV and JSON download controls. Exports use the data
|
|
4
|
+
already loaded in the browser; downloading does not request more history or trigger
|
|
5
|
+
a process scan. Access remains scoped to the signed-in user's machines.
|
|
6
|
+
|
|
7
|
+
## History
|
|
8
|
+
|
|
9
|
+
Exports include the selected metrics and visible series. Hidden GPU cards and
|
|
10
|
+
legend series are excluded. The document records the machine, time range, units,
|
|
11
|
+
load time, resolution and partial-result status. Rolled-up buckets retain their
|
|
12
|
+
minimum, maximum and average; these are not individual raw samples.
|
|
13
|
+
|
|
14
|
+
Unavailable numeric values remain empty in CSV and null in JSON. Recorded gaps
|
|
15
|
+
include their interval and available reason/drop count. Selected metrics without
|
|
16
|
+
stored data are identified separately. The JSON summary's
|
|
17
|
+
`averageOfBucketAverages` is an average of the loaded buckets, not a weighted
|
|
18
|
+
average of all underlying raw samples.
|
|
19
|
+
|
|
20
|
+
The CSV begins with metadata rows, followed by a `record_type` table containing
|
|
21
|
+
`bucket` and `gap` records. JSON includes equivalent structured metadata and series.
|
|
22
|
+
|
|
23
|
+
## Processes
|
|
24
|
+
|
|
25
|
+
Exports follow the current search, sort and view. Application view includes each
|
|
26
|
+
matching group's processes; tree view retains depth. Snapshot capture time,
|
|
27
|
+
receipt time, freshness, unreadable-process count and collector truncation are
|
|
28
|
+
included. A paused or stale snapshot is labeled accordingly.
|
|
29
|
+
|
|
30
|
+
The exported fields are process name, PID, user, application/group, tree depth,
|
|
31
|
+
CPU percentage, resident memory, GPU memory, read/write rates and thread count.
|
|
32
|
+
Command arguments and environment data are not exported. CSV begins with snapshot
|
|
33
|
+
metadata, followed by the process table; JSON preserves the same scope explicitly.
|
|
34
|
+
|
|
35
|
+
## Files
|
|
36
|
+
|
|
37
|
+
Downloads use a machine slug and UTC timestamp. Text cells that could be treated
|
|
38
|
+
as spreadsheet formulas receive an apostrophe prefix in CSV. Numeric measurements
|
|
39
|
+
remain numeric. JSON preserves original text without spreadsheet-specific changes.
|
|
@@ -0,0 +1,477 @@
|
|
|
1
|
+
# Installation
|
|
2
|
+
|
|
3
|
+
## Install a release
|
|
4
|
+
|
|
5
|
+
Linux, Node.js 26+ with npm and a working systemd user manager are required for
|
|
6
|
+
background installation. Install Node.js before running Rigscope; the user installer
|
|
7
|
+
uses the selected Node executable. No global npm installation or source checkout is needed:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npx --yes rigscope@latest install --boot
|
|
11
|
+
~/.local/bin/rigscope
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
If the npm release is not available yet, use [Install from an archive](#install-from-an-archive).
|
|
15
|
+
|
|
16
|
+
Save the generated `owner` password. Open the printed dashboard URL. The installer
|
|
17
|
+
starts a verified background service and returns to the shell. Closing the terminal
|
|
18
|
+
does not stop it. The service restarts after crashes. `--boot` runs
|
|
19
|
+
`loginctl enable-linger` for the current user so startup does not require a login;
|
|
20
|
+
if host authorization prevents it, the installer reports the exact recovery command.
|
|
21
|
+
Omit `--boot` to start at login only. `status` reports the actual startup setting.
|
|
22
|
+
|
|
23
|
+
`--no-start` leaves a new installation stopped, and `--no-enable` disables login
|
|
24
|
+
startup. Repeating `install` repairs registration/launcher and startup settings
|
|
25
|
+
without replacing the runtime or credentials; use `rigscope upgrade` to change code.
|
|
26
|
+
Re-registration with `--no-start` leaves an already-running service running.
|
|
27
|
+
|
|
28
|
+
| Goal | Install options | Runs |
|
|
29
|
+
| --- | --- | --- |
|
|
30
|
+
| Monitor this computer | `install --boot` | Background hub and local collector |
|
|
31
|
+
| Connect to a hub | `install --role collector --boot` | Collector after enrollment |
|
|
32
|
+
| Host and monitor through HTTPS | `install --origin https://hub.example.com --boot` | Background hub and colocated collector |
|
|
33
|
+
| Dedicated remote dashboard | `install --role hub --origin https://hub.example.com --boot` | Hub without collection |
|
|
34
|
+
| Foreground evaluation | `try` | Isolated hub and collector on port 8082 |
|
|
35
|
+
|
|
36
|
+
Add `~/.local/bin` to PATH if necessary. The generated command is a small launcher
|
|
37
|
+
that pins the installation's Node executable, state directory and stable managed
|
|
38
|
+
runtime path. It survives deletion of an npx cache or the original source checkout.
|
|
39
|
+
The service uses the same Node and runtime. An unrelated command at the destination
|
|
40
|
+
is preserved and the installer prints the usable absolute command path instead.
|
|
41
|
+
An owned symlink into the checkout used for installation is replaced by the managed
|
|
42
|
+
launcher. `install --from /path/release.tgz` can also stage a supplied archive.
|
|
43
|
+
|
|
44
|
+
### Install from an archive
|
|
45
|
+
|
|
46
|
+
For testing before npm publication, or for a downloaded release, run from the
|
|
47
|
+
directory containing the archive or supply its absolute path:
|
|
48
|
+
|
|
49
|
+
```sh
|
|
50
|
+
npx --yes --package ./rigscope-0.1.0.tgz rigscope install --boot
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The archive contains the built application. npm still needs access to its registry
|
|
54
|
+
or a populated cache to install production dependencies. A `.tgz` alone is not a
|
|
55
|
+
complete offline installation. All role, origin and startup options below also
|
|
56
|
+
work with the archive command.
|
|
57
|
+
|
|
58
|
+
## Everyday commands and installation selection
|
|
59
|
+
|
|
60
|
+
Bare `rigscope` shows status and never initializes state or starts a trial.
|
|
61
|
+
`start` is idempotent. `status` includes scope, role, startup, PID, CLI/runtime
|
|
62
|
+
versions, and live hub health/version when a user service is active. `logs` shows
|
|
63
|
+
100 journal lines; `logs --follow` follows new entries.
|
|
64
|
+
|
|
65
|
+
```sh
|
|
66
|
+
rigscope
|
|
67
|
+
rigscope start
|
|
68
|
+
rigscope stop
|
|
69
|
+
rigscope logs --follow
|
|
70
|
+
rigscope upgrade
|
|
71
|
+
rigscope uninstall
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`uninstall` removes both user services, their matching launcher and installed runtime
|
|
75
|
+
copies, preserving accounts, history, identity, queues and backups. Reinstall
|
|
76
|
+
using npm or an archive to restore the application with retained settings. No data purge is implicit.
|
|
77
|
+
|
|
78
|
+
## Access from another computer
|
|
79
|
+
|
|
80
|
+
For a new installation, set the browser-visible HTTPS origin at install time:
|
|
81
|
+
|
|
82
|
+
```sh
|
|
83
|
+
npx --yes rigscope@latest install \
|
|
84
|
+
--origin https://machine.example.ts.net:8081 --boot
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
The default `local` role means a colocated hub and collector. It supports either
|
|
88
|
+
localhost or HTTPS access. Its collector uses the configured HTTPS endpoint, with
|
|
89
|
+
normal certificate validation and its existing machine credential. No second
|
|
90
|
+
collector or grant is needed. Use `--role hub` for an initial dashboard without
|
|
91
|
+
collection, then `rigscope enable collector` to add collection later.
|
|
92
|
+
`enable` and `disable` control each component independently; `start`, `stop`,
|
|
93
|
+
`restart` and `logs` accept `hub` or `collector`.
|
|
94
|
+
For a hub-first setup, install `--role hub`, then enroll a separate collector using **Add machine**.
|
|
95
|
+
|
|
96
|
+
Run the HTTPS proxy on the hub machine. With Tailscale already configured, preserve
|
|
97
|
+
other Serve routes and use TLS-terminated TCP forwarding to preserve Rigscope's
|
|
98
|
+
exact Host/Origin boundary:
|
|
99
|
+
|
|
100
|
+
```sh
|
|
101
|
+
tailscale serve --bg --tls-terminated-tcp=8081 \
|
|
102
|
+
"unix:$HOME/.local/state/rigscope/run/hub.sock"
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Use the actual socket printed by the installer if selecting another state directory.
|
|
106
|
+
Open the configured HTTPS origin from a computer permitted to reach the hub through
|
|
107
|
+
Tailscale. The viewing computer needs no Rigscope installation unless it should
|
|
108
|
+
also be monitored. The background proxy and Rigscope service continue after closing
|
|
109
|
+
the terminal.
|
|
110
|
+
|
|
111
|
+
### Convert a retained localhost installation
|
|
112
|
+
|
|
113
|
+
`uninstall` removes services, the command and runtime copies, while preserving
|
|
114
|
+
configuration, accounts, history, identity and queues. A reinstall with different role or
|
|
115
|
+
origin settings therefore refuses rather than silently resetting that state.
|
|
116
|
+
Change access explicitly instead:
|
|
117
|
+
|
|
118
|
+
```sh
|
|
119
|
+
rigscope stop
|
|
120
|
+
rigscope configure --origin https://machine.example.ts.net:8081
|
|
121
|
+
rigscope start
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
`configure` requires a stopped hub and also a stopped collector when its colocated
|
|
125
|
+
destination changes. It validates the new origin/socket, backs up the
|
|
126
|
+
previous private settings, and updates the colocated collector's matching destination.
|
|
127
|
+
It moves that destination's entire outbox, including SQLite WAL, without changing
|
|
128
|
+
credentials or other hubs. An existing target outbox refuses conversion to avoid
|
|
129
|
+
merging or discarding pending records. Accounts and the history database are untouched.
|
|
130
|
+
Run `configure --local` while stopped to return to localhost. Rollback targets must declare support for the saved configuration and database schema.
|
|
131
|
+
|
|
132
|
+
If already uninstalled, configure retained state through the package entry point,
|
|
133
|
+
then reinstall the full application:
|
|
134
|
+
|
|
135
|
+
```sh
|
|
136
|
+
npx --yes rigscope@latest configure \
|
|
137
|
+
--origin https://machine.example.ts.net:8081
|
|
138
|
+
npx --yes rigscope@latest install --boot
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Before npm publication, substitute the archive entry point shown above.
|
|
142
|
+
Users, history and identity remain intact when restoring the launcher/services.
|
|
143
|
+
|
|
144
|
+
## Add machines and hubs
|
|
145
|
+
|
|
146
|
+
1. Install the collector role on the new machine. It stays stopped until enrolled.
|
|
147
|
+
2. On the hub choose **Add machine**, then **New machine** and create a connection
|
|
148
|
+
grant. Grants are single-use and expire within 15 minutes.
|
|
149
|
+
3. Run the displayed `rigscope connect https://hub.example.com` command on the new
|
|
150
|
+
machine. Paste the grant at its private prompt.
|
|
151
|
+
4. The installed collector starts in the background after successful enrollment.
|
|
152
|
+
Use `--no-start` to enroll without starting.
|
|
153
|
+
|
|
154
|
+
On the collector machine:
|
|
155
|
+
|
|
156
|
+
```sh
|
|
157
|
+
npx --yes rigscope@latest install --role collector --boot
|
|
158
|
+
~/.local/bin/rigscope connect https://hub.example.com
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Stop a running collector before changing destinations. Replacement uses a grant
|
|
162
|
+
explicitly bound to the existing machine and `connect --replace`.
|
|
163
|
+
For unattended enrollment, put the grant in an owned private regular file and use
|
|
164
|
+
`--token-file /private/path`. It is never accepted as a command-line token. Delete
|
|
165
|
+
the file after use. Generated commands contain no grants, and clipboard contents
|
|
166
|
+
remain under the user's control.
|
|
167
|
+
|
|
168
|
+
Collectors connect outbound: no incoming collector port and no root collector are
|
|
169
|
+
needed. Each collector samples once and reports independently to up to eight hubs.
|
|
170
|
+
Retry queues persist across restart. CPU, memory, swap, GPU, disk, network rates and
|
|
171
|
+
on-demand processes are shared by default. Network addresses and full process
|
|
172
|
+
arguments are disabled. Per-hub sharing settings are in `collector/state.json`;
|
|
173
|
+
edit while stopped. Existing destinations keep their policies.
|
|
174
|
+
|
|
175
|
+
A hub has no fixed machine-count limit. Its concurrent connection budget defaults
|
|
176
|
+
to 100, configurable with `maxCollectorConnections` in private user `config.json`
|
|
177
|
+
or `HUB_MAX_COLLECTOR_CONNECTIONS` for raw/system hub services. Restart after edits.
|
|
178
|
+
|
|
179
|
+
## Explicit foreground trial
|
|
180
|
+
|
|
181
|
+
```sh
|
|
182
|
+
rigscope try
|
|
183
|
+
# Ctrl+C stops the trial hub and collector.
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
The default trial uses a separate `~/.local/state/rigscope-trial` directory and
|
|
187
|
+
port 8082. Trial credentials/history persist. `try --state-dir PATH --port PORT`
|
|
188
|
+
selects another trial. A managed runtime directory cannot be used for `try`.
|
|
189
|
+
`start --foreground` intentionally runs an existing installation in the terminal;
|
|
190
|
+
stop its background service first. It does not install a systemd service.
|
|
191
|
+
|
|
192
|
+
From source, prepare an archive with `npm ci` then `npm run package:npm`.
|
|
193
|
+
End users run the built package; they do not need a source build or checkout deployment command.
|
|
194
|
+
|
|
195
|
+
## Hub configuration
|
|
196
|
+
|
|
197
|
+
`rigscope config` prints the owned 0600 `config.json` path. `--state-dir PATH` or
|
|
198
|
+
`RIGSCOPE_STATE_DIR` selects another installation; directories must be private (0700).
|
|
199
|
+
Each installation has separate hashed hub and collector service names. The installed alias defaults to
|
|
200
|
+
the state directory it belongs to. Settings include the initial role preset, independent component enablement, local port, remote origin,
|
|
201
|
+
socket, bootstrap users and local collector mapping. Restart after edits. Managed hub
|
|
202
|
+
users become authoritative in SQLite after the first start; editing bootstrap password
|
|
203
|
+
hashes later does not change existing accounts. Use Administration for user changes.
|
|
204
|
+
|
|
205
|
+
A new hub prints an `owner` password once and stores only a salted scrypt hash. Save
|
|
206
|
+
that password. Local trial mode always listens on loopback and still requires login.
|
|
207
|
+
The trial persists real samples and identity; restarting it reuses the same credentials.
|
|
208
|
+
|
|
209
|
+
For a remote hub, forward the exact configured HTTPS origin to its private Unix socket,
|
|
210
|
+
for example with Tailscale Serve or a TLS reverse proxy running as the same user.
|
|
211
|
+
Configure the proxy separately and keep the socket private. The hub opens no plaintext
|
|
212
|
+
TCP listener in this mode; remote collectors use normal certificate-validated WSS.
|
|
213
|
+
Do not turn off TLS verification or expose the local trial listener to a LAN.
|
|
214
|
+
See the [HTTPS boundary](development.md#https-boundary) for proxy requirements.
|
|
215
|
+
|
|
216
|
+
## Upgrades
|
|
217
|
+
|
|
218
|
+
Use the installed command to upgrade the managed runtime and preserve its data:
|
|
219
|
+
|
|
220
|
+
```sh
|
|
221
|
+
rigscope upgrade # latest published npm release
|
|
222
|
+
rigscope upgrade --from rigscope@0.1.0 # select an exact published version
|
|
223
|
+
rigscope upgrade --from ./rigscope-VERSION.tgz # select a local archive
|
|
224
|
+
rigscope rollback # return to the retained previous runtime
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Run only the command for the desired operation. A fresh installation has no
|
|
228
|
+
previous runtime to roll back to. Updating a global npm package does not update
|
|
229
|
+
the runtime managed by `rigscope install`.
|
|
230
|
+
|
|
231
|
+
`rigscope doctor` checks the installation's runtime, private configuration,
|
|
232
|
+
service, database, listener, TLS destinations and sensor access. `--json` produces
|
|
233
|
+
redacted structured output. Checks follow component enablement: a hub does not need
|
|
234
|
+
an enabled collector.
|
|
235
|
+
|
|
236
|
+
`rigscope upgrade --from ./rigscope-VERSION.tgz` stages while active components
|
|
237
|
+
run, then stops them, verifies runtime leases and preserves a consistent database
|
|
238
|
+
backup paired with the old runtime. After activation it checks the running hub's
|
|
239
|
+
embedded version, database schema/integrity and, for active collectors, a fresh
|
|
240
|
+
sampling marker from the collector process. `--timeout SECONDS` bounds activation
|
|
241
|
+
health verification. A failed activation stops the attempted runtime before restoring
|
|
242
|
+
the previous code and, when needed, its matching database copy. Recovery is verified
|
|
243
|
+
before it is called healthy; an unresolved recovery error is reported explicitly.
|
|
244
|
+
Only components running before the upgrade are restarted. Startup settings are
|
|
245
|
+
preserved independently. Inactive components stay inactive.
|
|
246
|
+
|
|
247
|
+
`rigscope rollback` uses `runtime-previous` and `release-state.json`. Compatible
|
|
248
|
+
current databases retain post-upgrade data. An incompatible schema needs the paired
|
|
249
|
+
pre-upgrade backup (or an explicit compatible `--backup PATH`); the replaced database
|
|
250
|
+
is backed up first. Missing pairings fail closed. Do not manually move runtimes or
|
|
251
|
+
run old code against newer schemas. Keep separate off-machine backups.
|
|
252
|
+
|
|
253
|
+
For a lost owner password, stop the installation and use
|
|
254
|
+
`rigscope recover-password --user owner`. Entry is private and confirmed twice;
|
|
255
|
+
noninteractive use requires `--password-file` naming an owned private regular file.
|
|
256
|
+
Recovery changes the durable managed user, records an audit event and invalidation
|
|
257
|
+
marker, and leaves bootstrap configuration, machine access and collector credentials
|
|
258
|
+
intact. It refuses a live database lease and does not create or elevate users.
|
|
259
|
+
The stopped hub's in-memory sessions are gone; restart and use the new password.
|
|
260
|
+
|
|
261
|
+
Without `--from`, upgrade requests `rigscope@latest`. Before the first npm
|
|
262
|
+
publication, use `--from` with a local archive.
|
|
263
|
+
|
|
264
|
+
## Hardware
|
|
265
|
+
|
|
266
|
+
Linux is the supported collection platform. CPU/memory/process counters use procfs,
|
|
267
|
+
not CPU-vendor-specific tools. ARM/RISC-V CPU naming recognizes their common fields;
|
|
268
|
+
CPU utilization continues to use per-core procfs counters.
|
|
269
|
+
|
|
270
|
+
| Hardware | Available readings | Limit |
|
|
271
|
+
| --- | --- | --- |
|
|
272
|
+
| NVIDIA | Utilization, dedicated memory, temperature, power; compute-process memory | Requires `nvidia-smi`; existing asynchronous bounded polling |
|
|
273
|
+
| AMD discrete GPU | Busy percentage, dedicated VRAM, temperature, power | Requires readable amdgpu sysfs/hwmon counters |
|
|
274
|
+
| AMD integrated GPU | Busy percentage and available hardware sensors | Driver-reported VRAM only; no synthesized shared-memory totals |
|
|
275
|
+
| Intel discrete or integrated GPU | Available hwmon temperature/power; optional driver-exposed busy/VRAM counters | No general Intel utilization/engine backend yet; most Intel utilization remains unavailable |
|
|
276
|
+
| ASPEED/other display adapters | Inventory | No telemetry backend |
|
|
277
|
+
|
|
278
|
+
On AMD APUs the reported power counter can include CPU/SoC power; it is not a
|
|
279
|
+
GPU-exclusive power measurement.
|
|
280
|
+
|
|
281
|
+
Every field is optional. Drivers, permissions and kernel versions determine what can
|
|
282
|
+
be read. An adapter with no readable counters remains unsupported; missing readings
|
|
283
|
+
never become successful zeros. Intel sensor presence does not imply utilization or
|
|
284
|
+
per-process GPU accounting support. Hotplug uses the existing inventory refresh.
|
|
285
|
+
AMD/Intel adapters retain PCI-based IDs, while NVIDIA retains its UUID-based IDs.
|
|
286
|
+
|
|
287
|
+
AMD uses the kernel's [amdgpu sysfs and hwmon interfaces](https://docs.kernel.org/gpu/amdgpu/thermal.html).
|
|
288
|
+
The Radeon 860M iGPU and RTX 5060 Laptop GPU have now been checked on the actual
|
|
289
|
+
laptop, including fresh iGPU utilization, driver-reported memory, temperature and
|
|
290
|
+
power samples persisted by the hub. The Ubuntu RTX 3090 rig remains validated. Intel
|
|
291
|
+
sensor and ARM/RISC-V naming paths have fixture coverage and still need physical
|
|
292
|
+
validation. macOS, Windows, Apple GPU telemetry and a
|
|
293
|
+
complete Intel GPU utilization backend are not included in this release pass.
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
## System installation
|
|
297
|
+
|
|
298
|
+
The optional system scope uses dedicated unprivileged accounts and starts at boot without user lingering. Review its plan before applying changes. Mutations require root and `--apply`; without `--apply` they print the proposed changes. The installed `rigscope system` command uses the same implementation as `dist/system.cjs`.
|
|
299
|
+
|
|
300
|
+
### Scope and generated layout
|
|
301
|
+
|
|
302
|
+
```text
|
|
303
|
+
/opt/rigscope/ root:root 0755
|
|
304
|
+
releases/<version>/ immutable root-owned release
|
|
305
|
+
current -> releases/<version>
|
|
306
|
+
previous -> releases/<previous> retained for rollback
|
|
307
|
+
node/node root-owned Node 26 when the selected binary was not root-owned
|
|
308
|
+
/etc/rigscope/
|
|
309
|
+
hub.env root:root 0600 (credentials, never printed)
|
|
310
|
+
collector.env root:root 0600
|
|
311
|
+
/var/lib/rigscope/
|
|
312
|
+
hub/telemetry.sqlite rigscope-hub 0600, private 0700 directory
|
|
313
|
+
hub/enrollment.json rigscope-hub 0600
|
|
314
|
+
hub/run/hub.sock private Unix socket (remote mode)
|
|
315
|
+
collector/state.json rigscope-collector 0600
|
|
316
|
+
collector/outbox/ durable collector outboxes
|
|
317
|
+
backups/ root:root 0700, pre-upgrade/pre-rollback SQLite copies
|
|
318
|
+
system-install.json root:root 0600, version 2 component state/versions/backups/adoption
|
|
319
|
+
power-access.json root:root 0600, original counter modes for reversal
|
|
320
|
+
/etc/systemd/system/rigscope-hub.service root:root 0644, hub boot unit
|
|
321
|
+
/etc/systemd/system/rigscope-collector.service root:root 0644, collector boot unit
|
|
322
|
+
/etc/sysusers.d/rigscope.conf root:root 0644, both nologin accounts
|
|
323
|
+
/etc/sysusers.d/rigscope-rapl.conf root:root 0644, collector-only power membership
|
|
324
|
+
/etc/udev/rules.d/90-rigscope-rapl.rules root:root 0644
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
Build the checkout before using `dist/system.cjs`; an installed package exposes the same commands through `rigscope system`. Reference copies are in `packaging/system/`. They are for review only; the
|
|
328
|
+
renderer in `src/cli/system.ts` is authoritative.
|
|
329
|
+
|
|
330
|
+
`systemd-sysusers` creates `rigscope-hub` and `rigscope-collector` as nologin
|
|
331
|
+
system accounts even when one component is disabled, so the other can be
|
|
332
|
+
enabled later without reinstalling. The hub and collector never run as root.
|
|
333
|
+
The units set `NoNewPrivileges=yes`, `ProtectSystem=strict`,
|
|
334
|
+
`ProtectHome=yes`, an empty `CapabilityBoundingSet=`/`AmbientCapabilities=`,
|
|
335
|
+
`UMask=0077`, explicit writable state paths and a read-only release tree. The
|
|
336
|
+
collector uses `--await-connection` to exit cleanly when no destinations are
|
|
337
|
+
configured, including after an interrupted enrollment. The
|
|
338
|
+
collector does **not** use `PrivateDevices=yes` because GPU telemetry still
|
|
339
|
+
needs real device nodes. The hub does.
|
|
340
|
+
|
|
341
|
+
### System component lifecycle
|
|
342
|
+
|
|
343
|
+
All mutating commands require `--apply` and root. Without `--apply`, the exact
|
|
344
|
+
files and command sequence are printed and nothing is written. Every component
|
|
345
|
+
operation touches only its own unit; enabling or starting one component never
|
|
346
|
+
stops or restarts the other.
|
|
347
|
+
|
|
348
|
+
```sh
|
|
349
|
+
# Package first (from a built checkout).
|
|
350
|
+
node scripts/package-release.cjs --output /var/tmp/rigscope-<version>.tar.gz
|
|
351
|
+
|
|
352
|
+
# Review a release before granting sudo.
|
|
353
|
+
node dist/system.cjs plan \
|
|
354
|
+
--source /var/tmp/rigscope-<version>.tar.gz --role local --node /usr/bin/node
|
|
355
|
+
|
|
356
|
+
# Install one complete package. --role selects the initial enabled preset.
|
|
357
|
+
sudo node dist/system.cjs install \
|
|
358
|
+
--source /var/tmp/rigscope-<version>.tar.gz --role hub \
|
|
359
|
+
--node /usr/bin/node --install-deps --enable --apply
|
|
360
|
+
|
|
361
|
+
# Add the other component later; no reinstall and no new package are needed.
|
|
362
|
+
sudo node dist/system.cjs enable collector --apply
|
|
363
|
+
sudo node dist/system.cjs enable hub --apply
|
|
364
|
+
|
|
365
|
+
# Component-specific lifecycle when both exist.
|
|
366
|
+
sudo node dist/system.cjs disable collector --apply
|
|
367
|
+
sudo node dist/system.cjs restart hub --apply
|
|
368
|
+
sudo node dist/system.cjs restart collector --apply
|
|
369
|
+
sudo node dist/system.cjs restart --apply # enabled components only
|
|
370
|
+
|
|
371
|
+
# Component-specific status and logs.
|
|
372
|
+
node dist/system.cjs status
|
|
373
|
+
node dist/system.cjs status collector --json
|
|
374
|
+
node dist/system.cjs logs hub --follow
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
`install` stages a complete release, verifies both runtimes and UI artifacts,
|
|
378
|
+
copies a non-root-owned Node executable into the root-owned prefix, installs
|
|
379
|
+
production dependencies when `--install-deps` is given, writes private
|
|
380
|
+
configuration and both units, creates both accounts, then switches `current`.
|
|
381
|
+
Staging happens before any service is stopped.
|
|
382
|
+
|
|
383
|
+
- With `--enable`, `--role local` initially enables both components.
|
|
384
|
+
- With `--enable`, `--role hub` initially enables only the hub.
|
|
385
|
+
- With `--enable`, `--role collector` initially enables only the collector.
|
|
386
|
+
- Without `--enable`, both components are installed but disabled.
|
|
387
|
+
- `--start` starts only the requested preset and verifies those components.
|
|
388
|
+
- `--without-power` skips the collector RAPL grant at that mutation.
|
|
389
|
+
|
|
390
|
+
`enable hub` creates the owner account once when `HUB_BROWSER_USERS` is empty
|
|
391
|
+
and prints the password only in that mutation. It is never stored in plaintext
|
|
392
|
+
or printed again. `enable collector` completes the collector account, unit,
|
|
393
|
+
identity and RAPL grant. With no destination it tries the colocated hub:
|
|
394
|
+
|
|
395
|
+
- A live configured hub gets a short-lived, single-use grant in its
|
|
396
|
+
authoritative SQLite registry. The collector then enrolls through the normal
|
|
397
|
+
hub API, which updates the live registry without stopping or restarting the
|
|
398
|
+
hub.
|
|
399
|
+
- A stopped hub gets the identity written to the authoritative registry (or a
|
|
400
|
+
static `HUB_COLLECTORS` bootstrap when the registry is not initialized yet);
|
|
401
|
+
enabling the collector never starts the hub.
|
|
402
|
+
- If there is no configured hub, the collector is enabled but stays dormant and
|
|
403
|
+
reports `Awaiting connection`. Its unit uses `--await-connection` to exit
|
|
404
|
+
cleanly before collection until a destination is saved.
|
|
405
|
+
|
|
406
|
+
Configured remote destinations and credentials are never overwritten. Re-running
|
|
407
|
+
`enable collector` leaves its destination, token, identity and outboxes intact.
|
|
408
|
+
|
|
409
|
+
### Connecting to an independent hub
|
|
410
|
+
|
|
411
|
+
For a hub-first test where the hub and collector are separate installations,
|
|
412
|
+
create a connection grant in the hub's admin Collectors panel. Save the grant to
|
|
413
|
+
a private file and connect the system collector:
|
|
414
|
+
|
|
415
|
+
```sh
|
|
416
|
+
# On the collector host; the grant file must be root-owned and 0600.
|
|
417
|
+
sudo install -m 0600 /dev/null /root/collector-grant
|
|
418
|
+
sudoedit /root/collector-grant # paste the single-use grant, save, quit
|
|
419
|
+
sudo node dist/system.cjs connect https://<hub-host> \
|
|
420
|
+
--token-file /root/collector-grant --apply
|
|
421
|
+
sudo rm /root/collector-grant
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
`connect` stops only the collector while it enrolls, calls the hub's normal
|
|
425
|
+
enrollment API, persists the issued credential under
|
|
426
|
+
`/var/lib/rigscope/collector/state.json`, and starts the collector if it is
|
|
427
|
+
enabled. The grant is never printed. Re-running `connect` on a configured
|
|
428
|
+
collector is refused rather than replacing a remote destination.
|
|
429
|
+
|
|
430
|
+
Status reports each component independently:
|
|
431
|
+
|
|
432
|
+
```text
|
|
433
|
+
Components:
|
|
434
|
+
hub: installed, enabled, active, ready
|
|
435
|
+
collector: installed, enabled, active, ready, 1 destination(s)
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
`readiness` is `ready`, `stopped`, `unconfigured`, `awaiting-connection`,
|
|
439
|
+
`invalid-config`, `invalid-state` or `missing`.
|
|
440
|
+
|
|
441
|
+
### CPU package power
|
|
442
|
+
|
|
443
|
+
`collector/sampling/hwmon.ts` already reads top-level RAPL package counters,
|
|
444
|
+
sums multiple sockets, handles wrap/reset and returns unavailable rather than
|
|
445
|
+
zero. On hosts where `energy_uj` is root-only, system scope grants a narrow
|
|
446
|
+
read path instead of elevating Node.
|
|
447
|
+
|
|
448
|
+
```sh
|
|
449
|
+
node dist/system.cjs power status
|
|
450
|
+
sudo node dist/system.cjs power grant --apply
|
|
451
|
+
sudo node dist/system.cjs power revoke --apply
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
Mechanism:
|
|
455
|
+
|
|
456
|
+
- `/etc/sysusers.d/rigscope-rapl.conf` creates `rigscope-rapl` and adds only
|
|
457
|
+
`rigscope-collector`; the hub is not a member.
|
|
458
|
+
- A `powercap` udev rule matches only top-level `intel-rapl:N` devices named
|
|
459
|
+
`package*` and changes only `energy_uj` and `max_energy_range_uj` to
|
|
460
|
+
`0440 root:rigscope-rapl`. Subdomains, constraint files and power-limit
|
|
461
|
+
writes are untouched.
|
|
462
|
+
- `udevadm trigger --subsystem-match=powercap --action=change` applies the rule
|
|
463
|
+
immediately. Because the rule lives in `/etc/udev/rules.d`, device
|
|
464
|
+
recreation and boot reapply it.
|
|
465
|
+
- The collector unit adds `SupplementaryGroups=rigscope-rapl`; it does not use
|
|
466
|
+
file capabilities, ambient capabilities or a privileged Node helper.
|
|
467
|
+
- Grant records each existing counter's original mode/uid/gid in
|
|
468
|
+
`/var/lib/rigscope/power-access.json`. Revoke removes the rule and group
|
|
469
|
+
membership and restores those recorded values (defaults `0400` for
|
|
470
|
+
`energy_uj` and `0444` for `max_energy_range_uj` when no record exists).
|
|
471
|
+
- `power status` reports driver modules, package domains, collector
|
|
472
|
+
readability, persistence, world readability and every problem. A missing
|
|
473
|
+
counter is reported unavailable, never as zero watts.
|
|
474
|
+
|
|
475
|
+
Verify real watts in History after granting access and restarting the collector;
|
|
476
|
+
do not treat a mocked value or a one-time manual `chmod` as installation
|
|
477
|
+
evidence. Unsupported hardware remains unavailable.
|