rigscope 0.1.8 → 0.2.1
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 -1
- package/.next/app-path-routes-manifest.json +1 -1
- package/.next/build-manifest.json +2 -2
- package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_global-error.html +1 -1
- package/.next/server/app/_global-error.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_not-found.html +1 -1
- package/.next/server/app/_not-found.rsc +3 -3
- package/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +3 -3
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/administration/page_client-reference-manifest.js +1 -1
- package/.next/server/app/administration.html +1 -1
- package/.next/server/app/administration.rsc +3 -3
- package/.next/server/app/administration.segments/_full.segment.rsc +3 -3
- package/.next/server/app/administration.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/administration.segments/administration/__PAGE__.segment.rsc +3 -3
- package/.next/server/app/alerts/page_client-reference-manifest.js +1 -1
- package/.next/server/app/alerts.html +1 -1
- package/.next/server/app/alerts.rsc +3 -3
- package/.next/server/app/alerts.segments/_full.segment.rsc +3 -3
- package/.next/server/app/alerts.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/alerts.segments/alerts/__PAGE__.segment.rsc +3 -3
- package/.next/server/app/connections/page.js +1 -1
- package/.next/server/app/connections/page_client-reference-manifest.js +1 -1
- package/.next/server/app/connections.html +1 -1
- package/.next/server/app/connections.rsc +4 -4
- package/.next/server/app/connections.segments/_full.segment.rsc +4 -4
- package/.next/server/app/connections.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/connections.segments/connections/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/history/page.js +2 -2
- package/.next/server/app/history/page_client-reference-manifest.js +1 -1
- package/.next/server/app/history.html +1 -1
- package/.next/server/app/history.rsc +6 -6
- package/.next/server/app/history.segments/_full.segment.rsc +6 -6
- package/.next/server/app/history.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/history.segments/history/__PAGE__.segment.rsc +6 -6
- package/.next/server/app/index.html +1 -1
- package/.next/server/app/index.rsc +3 -3
- package/.next/server/app/index.segments/__PAGE__.segment.rsc +3 -3
- package/.next/server/app/index.segments/_full.segment.rsc +3 -3
- package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/.next/server/app/login.html +1 -1
- package/.next/server/app/login.rsc +3 -3
- package/.next/server/app/login.segments/_full.segment.rsc +3 -3
- package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +3 -3
- package/.next/server/app/machines/[machineId]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/processes/page_client-reference-manifest.js +1 -1
- package/.next/server/app/processes.html +1 -1
- package/.next/server/app/processes.rsc +3 -3
- package/.next/server/app/processes.segments/_full.segment.rsc +3 -3
- package/.next/server/app/processes.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/processes.segments/processes/__PAGE__.segment.rsc +3 -3
- package/.next/server/app-paths-manifest.json +1 -1
- package/.next/server/chunks/161.js +1 -1
- package/.next/server/chunks/168.js +1 -1
- package/.next/server/middleware-build-manifest.js +1 -1
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/static/chunks/408-351fe4a1e9a2d556.js +1 -0
- package/.next/static/chunks/939-92930fde48061e20.js +1 -0
- package/.next/static/chunks/app/connections/page-7d18b901f2338f20.js +1 -0
- package/.next/static/chunks/app/history/page-adc25194b30c689d.js +3 -0
- package/.next/static/css/{f5d3162842dcac31.css → 2abef6d49c1c2970.css} +1 -1
- package/ARCHITECTURE.md +43 -15
- package/CHANGELOG.md +62 -0
- package/README.md +10 -3
- package/dist/cli.cjs +868 -511
- package/dist/collector.cjs +603 -120
- package/dist/hub.cjs +3429 -1451
- package/dist/ops.cjs +1178 -888
- package/dist/system.cjs +1322 -363
- package/docs/configuration.md +34 -1
- package/docs/installation.md +12 -6
- package/docs/monitoring.md +60 -17
- package/docs/operations.md +78 -22
- package/docs/system-installation.md +11 -4
- package/docs/telemetry-storage.md +258 -0
- package/package.json +3 -1
- package/packaging/collector.env.example +6 -0
- package/packaging/system/rigscope-collector.service.example +3 -0
- package/.next/static/chunks/408-9fdba9e4e956ef08.js +0 -1
- package/.next/static/chunks/939-514e554087419c71.js +0 -1
- package/.next/static/chunks/app/connections/page-75abd16fc495fcbd.js +0 -1
- package/.next/static/chunks/app/history/page-a25ba8fab7bd7cb9.js +0 -3
- /package/.next/static/{ip43TIgmaByEBn2GFtvfO → JbaLjudQSxrMUD_VHPrnD}/_buildManifest.js +0 -0
- /package/.next/static/{ip43TIgmaByEBn2GFtvfO → JbaLjudQSxrMUD_VHPrnD}/_ssgManifest.js +0 -0
package/dist/cli.cjs
CHANGED
|
@@ -23,8 +23,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
23
|
));
|
|
24
24
|
|
|
25
25
|
// src/cli/main.ts
|
|
26
|
-
var
|
|
27
|
-
var
|
|
26
|
+
var import_node_fs20 = require("node:fs");
|
|
27
|
+
var import_node_path21 = require("node:path");
|
|
28
28
|
var import_node_util2 = require("node:util");
|
|
29
29
|
var import_node_readline = require("node:readline");
|
|
30
30
|
var import_node_stream = require("node:stream");
|
|
@@ -42,6 +42,9 @@ var SHARING_KEYS = [
|
|
|
42
42
|
"processArguments"
|
|
43
43
|
];
|
|
44
44
|
|
|
45
|
+
// collector/destinations/queue.ts
|
|
46
|
+
var DEFAULT_COLLECTOR_QUEUE_MODE = "memory";
|
|
47
|
+
|
|
45
48
|
// collector/config.ts
|
|
46
49
|
var ConfigError = class extends Error {
|
|
47
50
|
issues;
|
|
@@ -247,6 +250,18 @@ function parseDestinations(env, issues, destinations) {
|
|
|
247
250
|
}
|
|
248
251
|
}
|
|
249
252
|
}
|
|
253
|
+
var QUEUE_MODES = ["memory", "durable"];
|
|
254
|
+
function parseQueueMode(env, issues) {
|
|
255
|
+
const raw = env["COLLECTOR_QUEUE_MODE"]?.trim();
|
|
256
|
+
if (raw === void 0 || raw === "") {
|
|
257
|
+
return DEFAULT_COLLECTOR_QUEUE_MODE;
|
|
258
|
+
}
|
|
259
|
+
if (!QUEUE_MODES.includes(raw)) {
|
|
260
|
+
issues.push(`COLLECTOR_QUEUE_MODE must be one of ${QUEUE_MODES.join(" or ")}`);
|
|
261
|
+
return DEFAULT_COLLECTOR_QUEUE_MODE;
|
|
262
|
+
}
|
|
263
|
+
return raw;
|
|
264
|
+
}
|
|
250
265
|
function parseIntervalMs(env, issues) {
|
|
251
266
|
const raw = env["COLLECTOR_INTERVAL_MS"]?.trim();
|
|
252
267
|
if (raw === void 0 || raw === "") {
|
|
@@ -277,6 +292,7 @@ function parseCollectorConfig(env) {
|
|
|
277
292
|
}
|
|
278
293
|
const destinations = [];
|
|
279
294
|
const intervalMs = parseIntervalMs(env, issues);
|
|
295
|
+
const queueMode = parseQueueMode(env, issues);
|
|
280
296
|
parseDestinations(env, issues, destinations);
|
|
281
297
|
if (issues.length > 0) {
|
|
282
298
|
throw new ConfigError(issues);
|
|
@@ -286,7 +302,8 @@ function parseCollectorConfig(env) {
|
|
|
286
302
|
hostname,
|
|
287
303
|
hostnameIsMockDefault: rawHostname === "",
|
|
288
304
|
intervalMs,
|
|
289
|
-
destinations
|
|
305
|
+
destinations,
|
|
306
|
+
queueMode
|
|
290
307
|
};
|
|
291
308
|
}
|
|
292
309
|
|
|
@@ -661,6 +678,13 @@ function verifyPassword(password, hash2) {
|
|
|
661
678
|
// src/hub/config.ts
|
|
662
679
|
var import_node_net = require("node:net");
|
|
663
680
|
var import_node_path3 = require("node:path");
|
|
681
|
+
|
|
682
|
+
// src/contracts/telemetry.ts
|
|
683
|
+
var MAX_PERSISTENT_FLUSH_MS = 5e3;
|
|
684
|
+
var MIN_EPOCH = Date.parse("2000-01-01T00:00:00Z");
|
|
685
|
+
var MAX_EPOCH = Date.parse("2200-01-01T00:00:00Z");
|
|
686
|
+
|
|
687
|
+
// src/hub/config.ts
|
|
664
688
|
var MAX_HUB_COLLECTORS_BYTES = 1024 * 1024;
|
|
665
689
|
var MAX_COLLECTOR_ID_LENGTH = 128;
|
|
666
690
|
var MAX_MACHINE_ID_LENGTH = 128;
|
|
@@ -688,6 +712,7 @@ function parseHubConfig(env) {
|
|
|
688
712
|
maxCollectorConnections = parsed;
|
|
689
713
|
}
|
|
690
714
|
const connectionBudget = maxCollectorConnections === void 0 ? {} : { maxCollectorConnections };
|
|
715
|
+
const history = parseHistoryConfig(env);
|
|
691
716
|
if (publicOrigin === void 0 !== (socketPath === void 0)) {
|
|
692
717
|
throw new HubConfigError(
|
|
693
718
|
"HUB_PUBLIC_ORIGIN and HUB_SOCKET_PATH must be set together: remote mode needs both the exact HTTPS origin and the Unix socket path"
|
|
@@ -707,6 +732,7 @@ function parseHubConfig(env) {
|
|
|
707
732
|
collectors,
|
|
708
733
|
development,
|
|
709
734
|
remote: parseRemoteConfig(publicOrigin, socketPath),
|
|
735
|
+
history,
|
|
710
736
|
...connectionBudget
|
|
711
737
|
};
|
|
712
738
|
}
|
|
@@ -716,9 +742,65 @@ function parseHubConfig(env) {
|
|
|
716
742
|
collectors,
|
|
717
743
|
development,
|
|
718
744
|
remote: null,
|
|
745
|
+
history,
|
|
719
746
|
...connectionBudget
|
|
720
747
|
};
|
|
721
748
|
}
|
|
749
|
+
var DEFAULT_MEMORY_BUDGET_BYTES = 128 * 1024 * 1024;
|
|
750
|
+
var DEFAULT_PERSISTENT_FLUSH_MS = MAX_PERSISTENT_FLUSH_MS;
|
|
751
|
+
var DEFAULT_RECORDING_MAX_DURATION_MS = 60 * 6e4;
|
|
752
|
+
var DEFAULT_RECORDING_MAX_BYTES = 64 * 1024 * 1024;
|
|
753
|
+
var DEFAULT_RECORDING_BACKLOG_MS = 10 * 6e4;
|
|
754
|
+
var DEFAULT_MAX_ACTIVE_RECORDINGS = 4;
|
|
755
|
+
var HOUR_MS = 36e5;
|
|
756
|
+
var DAY_MS = 864e5;
|
|
757
|
+
function parseHistoryConfig(env) {
|
|
758
|
+
const modeValue = env.HUB_TELEMETRY_MODE ?? "memory";
|
|
759
|
+
if (modeValue !== "memory" && modeValue !== "persistent") {
|
|
760
|
+
throw new HubConfigError("HUB_TELEMETRY_MODE must be memory or persistent");
|
|
761
|
+
}
|
|
762
|
+
const memoryBudgetBytes = envInteger(
|
|
763
|
+
env.HUB_HISTORY_MEMORY_BYTES,
|
|
764
|
+
DEFAULT_MEMORY_BUDGET_BYTES,
|
|
765
|
+
1 * 1024 * 1024,
|
|
766
|
+
16 * 1024 * 1024 * 1024,
|
|
767
|
+
"HUB_HISTORY_MEMORY_BYTES"
|
|
768
|
+
);
|
|
769
|
+
const flushIntervalMs = envInteger(
|
|
770
|
+
env.HUB_TELEMETRY_FLUSH_MS,
|
|
771
|
+
DEFAULT_PERSISTENT_FLUSH_MS,
|
|
772
|
+
1e3,
|
|
773
|
+
MAX_PERSISTENT_FLUSH_MS,
|
|
774
|
+
"HUB_TELEMETRY_FLUSH_MS"
|
|
775
|
+
);
|
|
776
|
+
const retention = {
|
|
777
|
+
rawMs: envInteger(env.HUB_RETENTION_RAW_MS, 2 * DAY_MS, 0, 400 * DAY_MS, "HUB_RETENTION_RAW_MS"),
|
|
778
|
+
tenSecondMs: envInteger(env.HUB_RETENTION_10S_MS, 2 * HOUR_MS, 0, 30 * DAY_MS, "HUB_RETENTION_10S_MS"),
|
|
779
|
+
oneMinuteMs: envInteger(env.HUB_RETENTION_1M_MS, 30 * DAY_MS, 0, 400 * DAY_MS, "HUB_RETENTION_1M_MS"),
|
|
780
|
+
oneHourMs: envInteger(env.HUB_RETENTION_1H_MS, 400 * DAY_MS, 0, 800 * DAY_MS, "HUB_RETENTION_1H_MS"),
|
|
781
|
+
receiptsMs: envInteger(env.HUB_RECEIPT_RETENTION_MS, 7 * DAY_MS, HOUR_MS, 400 * DAY_MS, "HUB_RECEIPT_RETENTION_MS"),
|
|
782
|
+
gapsMs: envInteger(env.HUB_GAP_RETENTION_MS, 400 * DAY_MS, 0, 800 * DAY_MS, "HUB_GAP_RETENTION_MS")
|
|
783
|
+
};
|
|
784
|
+
const recordings = {
|
|
785
|
+
directory: nonEmpty(env.HUB_RECORDINGS_DIR) ?? null,
|
|
786
|
+
maxDurationMs: envInteger(env.HUB_RECORDING_MAX_DURATION_MS, DEFAULT_RECORDING_MAX_DURATION_MS, 1e3, 24 * 60 * 6e4, "HUB_RECORDING_MAX_DURATION_MS"),
|
|
787
|
+
maxBytes: envInteger(env.HUB_RECORDING_MAX_BYTES, DEFAULT_RECORDING_MAX_BYTES, 64 * 1024, 1024 * 1024 * 1024, "HUB_RECORDING_MAX_BYTES"),
|
|
788
|
+
backlogMs: envInteger(env.HUB_RECORDING_BACKLOG_MS, DEFAULT_RECORDING_BACKLOG_MS, 0, 24 * 60 * 6e4, "HUB_RECORDING_BACKLOG_MS"),
|
|
789
|
+
maxActive: envInteger(env.HUB_RECORDING_MAX_ACTIVE, DEFAULT_MAX_ACTIVE_RECORDINGS, 1, 32, "HUB_RECORDING_MAX_ACTIVE")
|
|
790
|
+
};
|
|
791
|
+
return { mode: modeValue, memoryBudgetBytes, flushIntervalMs, retention, recordings };
|
|
792
|
+
}
|
|
793
|
+
function envInteger(raw, fallback, min, max, name) {
|
|
794
|
+
if (raw === void 0 || raw === "") return fallback;
|
|
795
|
+
if (!/^\d+$/.test(raw)) {
|
|
796
|
+
throw new HubConfigError(`${name} must be a nonnegative integer`);
|
|
797
|
+
}
|
|
798
|
+
const value = Number(raw);
|
|
799
|
+
if (!Number.isSafeInteger(value) || value < min || value > max) {
|
|
800
|
+
throw new HubConfigError(`${name} must be between ${min} and ${max}`);
|
|
801
|
+
}
|
|
802
|
+
return value;
|
|
803
|
+
}
|
|
722
804
|
function nonEmpty(value) {
|
|
723
805
|
return value === void 0 || value === "" ? void 0 : value;
|
|
724
806
|
}
|
|
@@ -1446,8 +1528,45 @@ var MIGRATIONS = [
|
|
|
1446
1528
|
},
|
|
1447
1529
|
{ version: 3, name: "admin", up: adminSchema },
|
|
1448
1530
|
{ version: 4, name: "alerts", up: installAlertSchema },
|
|
1449
|
-
{ version: 5, name: "collector_registry", up: installRegistrySchema }
|
|
1531
|
+
{ version: 5, name: "collector_registry", up: installRegistrySchema },
|
|
1532
|
+
{ version: 6, name: "telemetry_modes_and_recordings", up: telemetryModesAndRecordings }
|
|
1450
1533
|
];
|
|
1534
|
+
function telemetryModesAndRecordings(db) {
|
|
1535
|
+
db.exec(`
|
|
1536
|
+
CREATE TABLE IF NOT EXISTS points_10s (
|
|
1537
|
+
series_id INTEGER NOT NULL,
|
|
1538
|
+
bucket_ms INTEGER NOT NULL,
|
|
1539
|
+
min REAL,
|
|
1540
|
+
max REAL,
|
|
1541
|
+
sum REAL NOT NULL DEFAULT 0,
|
|
1542
|
+
count INTEGER NOT NULL DEFAULT 0,
|
|
1543
|
+
null_count INTEGER NOT NULL DEFAULT 0,
|
|
1544
|
+
PRIMARY KEY (series_id, bucket_ms)
|
|
1545
|
+
) WITHOUT ROWID;
|
|
1546
|
+
|
|
1547
|
+
CREATE TABLE IF NOT EXISTS recordings (
|
|
1548
|
+
id TEXT PRIMARY KEY,
|
|
1549
|
+
created_by TEXT NOT NULL,
|
|
1550
|
+
status TEXT NOT NULL,
|
|
1551
|
+
machines_json TEXT NOT NULL,
|
|
1552
|
+
metrics_json TEXT NOT NULL,
|
|
1553
|
+
resolution_ms INTEGER NOT NULL,
|
|
1554
|
+
created_at_ms INTEGER NOT NULL,
|
|
1555
|
+
started_at_ms INTEGER NOT NULL,
|
|
1556
|
+
stopped_at_ms INTEGER,
|
|
1557
|
+
deadline_ms INTEGER NOT NULL,
|
|
1558
|
+
max_bytes INTEGER NOT NULL,
|
|
1559
|
+
bytes_written INTEGER NOT NULL DEFAULT 0,
|
|
1560
|
+
file_name TEXT NOT NULL,
|
|
1561
|
+
include_backlog INTEGER NOT NULL DEFAULT 0,
|
|
1562
|
+
reason TEXT,
|
|
1563
|
+
error TEXT
|
|
1564
|
+
);
|
|
1565
|
+
|
|
1566
|
+
CREATE INDEX IF NOT EXISTS recordings_created
|
|
1567
|
+
ON recordings (created_at_ms DESC);
|
|
1568
|
+
`);
|
|
1569
|
+
}
|
|
1451
1570
|
|
|
1452
1571
|
// src/hub/storage/db.ts
|
|
1453
1572
|
var BUSY_TIMEOUT_MS = 5e3;
|
|
@@ -1524,7 +1643,7 @@ var SqliteHubDatabase = class {
|
|
|
1524
1643
|
const walBudgetBytes = Math.max(64 * 1024, Math.min(HUB_WAL_RESERVE_BYTES, Math.floor(limitBytes / 16)));
|
|
1525
1644
|
const mainBudgetBytes = Math.max(pageSize, limitBytes - walBudgetBytes);
|
|
1526
1645
|
const requestedPages = Math.max(1, Math.floor(mainBudgetBytes / pageSize));
|
|
1527
|
-
const checkpointPages = Math.max(16, Math.min(
|
|
1646
|
+
const checkpointPages = Math.max(16, Math.min(16384, Math.floor(walBudgetBytes / pageSize)));
|
|
1528
1647
|
this.db.exec(`PRAGMA journal_size_limit = ${walBudgetBytes}`);
|
|
1529
1648
|
this.db.exec(`PRAGMA wal_autocheckpoint = ${checkpointPages}`);
|
|
1530
1649
|
let maxPageCount = requestedPages;
|
|
@@ -3522,17 +3641,17 @@ function uninstallInstallation(dir, purge = true, injected = {}) {
|
|
|
3522
3641
|
|
|
3523
3642
|
// src/cli/mutation.ts
|
|
3524
3643
|
var import_node_child_process3 = require("node:child_process");
|
|
3525
|
-
var
|
|
3526
|
-
var
|
|
3644
|
+
var import_node_fs14 = require("node:fs");
|
|
3645
|
+
var import_node_path15 = require("node:path");
|
|
3527
3646
|
var import_promises = require("node:readline/promises");
|
|
3528
3647
|
|
|
3529
3648
|
// src/cli/lifecycle.ts
|
|
3530
|
-
var
|
|
3531
|
-
var
|
|
3649
|
+
var import_node_fs13 = require("node:fs");
|
|
3650
|
+
var import_node_path14 = require("node:path");
|
|
3532
3651
|
|
|
3533
3652
|
// src/cli/upgrade.ts
|
|
3534
|
-
var
|
|
3535
|
-
var
|
|
3653
|
+
var import_node_fs12 = require("node:fs");
|
|
3654
|
+
var import_node_path13 = require("node:path");
|
|
3536
3655
|
|
|
3537
3656
|
// src/operations/database.ts
|
|
3538
3657
|
var import_node_fs10 = require("node:fs");
|
|
@@ -3555,7 +3674,9 @@ var COUNTED_TABLES = /* @__PURE__ */ new Set([
|
|
|
3555
3674
|
"machine_meta",
|
|
3556
3675
|
"machine_latest",
|
|
3557
3676
|
"inventory",
|
|
3677
|
+
"points_10s",
|
|
3558
3678
|
"gaps",
|
|
3679
|
+
"recordings",
|
|
3559
3680
|
"alert_rules",
|
|
3560
3681
|
"alert_incidents",
|
|
3561
3682
|
"alert_jobs",
|
|
@@ -3878,6 +3999,187 @@ async function restoreDatabase(options) {
|
|
|
3878
3999
|
throw error2;
|
|
3879
4000
|
}
|
|
3880
4001
|
}
|
|
4002
|
+
var MACHINE_HISTORY_TABLES = [
|
|
4003
|
+
"points_raw",
|
|
4004
|
+
"points_10s",
|
|
4005
|
+
"points_1m",
|
|
4006
|
+
"points_1h",
|
|
4007
|
+
"sample_receipts",
|
|
4008
|
+
"gaps",
|
|
4009
|
+
"machine_latest",
|
|
4010
|
+
"inventory",
|
|
4011
|
+
"alert_observed_resources",
|
|
4012
|
+
"alert_machine_progress",
|
|
4013
|
+
"alert_incidents",
|
|
4014
|
+
"series"
|
|
4015
|
+
];
|
|
4016
|
+
function clearMachineHistory(database) {
|
|
4017
|
+
const path2 = resolvePath(database, "database");
|
|
4018
|
+
if (!(0, import_node_fs10.existsSync)(path2)) return { deleted: {}, integrity: "absent" };
|
|
4019
|
+
assertPrivateRegularFile(path2, "database");
|
|
4020
|
+
assertNoActiveHubLock(path2);
|
|
4021
|
+
const db = new import_node_sqlite2.DatabaseSync(path2, { timeout: BUSY_TIMEOUT_MS2 });
|
|
4022
|
+
const deleted = {};
|
|
4023
|
+
try {
|
|
4024
|
+
db.exec("PRAGMA busy_timeout = 5000");
|
|
4025
|
+
const present = new Set(
|
|
4026
|
+
db.prepare("SELECT name FROM sqlite_master WHERE type = 'table'").all().map((row) => row.name)
|
|
4027
|
+
);
|
|
4028
|
+
db.exec("BEGIN IMMEDIATE");
|
|
4029
|
+
try {
|
|
4030
|
+
for (const table of MACHINE_HISTORY_TABLES) {
|
|
4031
|
+
if (!present.has(table)) continue;
|
|
4032
|
+
const result = db.prepare(`DELETE FROM ${table}`).run();
|
|
4033
|
+
deleted[table] = Number(result.changes);
|
|
4034
|
+
}
|
|
4035
|
+
db.exec("COMMIT");
|
|
4036
|
+
} catch (error2) {
|
|
4037
|
+
try {
|
|
4038
|
+
db.exec("ROLLBACK");
|
|
4039
|
+
} catch {
|
|
4040
|
+
}
|
|
4041
|
+
throw error2;
|
|
4042
|
+
}
|
|
4043
|
+
const autoVacuum = db.prepare("PRAGMA auto_vacuum").get();
|
|
4044
|
+
if (autoVacuum && Object.values(autoVacuum)[0] === 2) db.exec("PRAGMA incremental_vacuum(1024)");
|
|
4045
|
+
try {
|
|
4046
|
+
db.exec("PRAGMA wal_checkpoint(TRUNCATE)");
|
|
4047
|
+
} catch {
|
|
4048
|
+
}
|
|
4049
|
+
} finally {
|
|
4050
|
+
db.close();
|
|
4051
|
+
}
|
|
4052
|
+
return { deleted, integrity: inspectDatabase(path2).integrity };
|
|
4053
|
+
}
|
|
4054
|
+
|
|
4055
|
+
// src/cli/machine-transition.ts
|
|
4056
|
+
var import_node_fs11 = require("node:fs");
|
|
4057
|
+
var import_node_path12 = require("node:path");
|
|
4058
|
+
var import_node_crypto11 = require("node:crypto");
|
|
4059
|
+
var MACHINE_DATA_TRANSITION_FILE = "machine-data-transition.json";
|
|
4060
|
+
var STAGED_QUEUE_PREFIX = "outbox.pre-transition-";
|
|
4061
|
+
function machineDataTransitionPath(stateRoot) {
|
|
4062
|
+
return (0, import_node_path12.join)(stateRoot, MACHINE_DATA_TRANSITION_FILE);
|
|
4063
|
+
}
|
|
4064
|
+
function readMachineDataTransition(stateRoot) {
|
|
4065
|
+
const path2 = machineDataTransitionPath(stateRoot);
|
|
4066
|
+
try {
|
|
4067
|
+
const stat = (0, import_node_fs11.lstatSync)(path2);
|
|
4068
|
+
if (!stat.isFile() || stat.isSymbolicLink() || (stat.mode & 63) !== 0) {
|
|
4069
|
+
throw new Error("marker must be a private regular file");
|
|
4070
|
+
}
|
|
4071
|
+
const value = JSON.parse((0, import_node_fs11.readFileSync)(path2, "utf8"));
|
|
4072
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) throw new Error("invalid marker");
|
|
4073
|
+
const record = value;
|
|
4074
|
+
if (typeof record.transitionedAt !== "string" || !Number.isFinite(Date.parse(record.transitionedAt))) {
|
|
4075
|
+
throw new Error("invalid transition date");
|
|
4076
|
+
}
|
|
4077
|
+
return { transitionedAt: record.transitionedAt, release: typeof record.release === "string" ? record.release : null };
|
|
4078
|
+
} catch (error2) {
|
|
4079
|
+
if (error2.code === "ENOENT") return null;
|
|
4080
|
+
throw new OperationsError(
|
|
4081
|
+
"invalid-transition-marker",
|
|
4082
|
+
`Cannot determine whether the one-time reset completed; preserving machine data. Repair ${path2}: ${errorMessage(error2)}`,
|
|
4083
|
+
{ cause: error2 }
|
|
4084
|
+
);
|
|
4085
|
+
}
|
|
4086
|
+
}
|
|
4087
|
+
function recordMachineDataTransition(stateRoot, release, write = (path2, content) => writePrivateFile(path2, content)) {
|
|
4088
|
+
const marker = { transitionedAt: (/* @__PURE__ */ new Date()).toISOString(), release };
|
|
4089
|
+
write(machineDataTransitionPath(stateRoot), `${JSON.stringify(marker, null, 2)}
|
|
4090
|
+
`);
|
|
4091
|
+
}
|
|
4092
|
+
function newMachineDataCleanup(transitioned) {
|
|
4093
|
+
return {
|
|
4094
|
+
report: { transitioned, databaseRows: null, collectorQueuesRemoved: false, warning: null },
|
|
4095
|
+
stagedQueues: null,
|
|
4096
|
+
databaseCleared: false
|
|
4097
|
+
};
|
|
4098
|
+
}
|
|
4099
|
+
function performMachineDataCleanup(stateRoot, paths, now = Date.now, deps = {}) {
|
|
4100
|
+
if (readMachineDataTransition(stateRoot) !== null) return newMachineDataCleanup(false);
|
|
4101
|
+
const cleanup = newMachineDataCleanup(true);
|
|
4102
|
+
const clear = deps.clear ?? clearMachineHistory;
|
|
4103
|
+
const warnings = [];
|
|
4104
|
+
try {
|
|
4105
|
+
if ((0, import_node_fs11.existsSync)(paths.queueTree)) {
|
|
4106
|
+
const staged = (0, import_node_path12.join)((0, import_node_path12.dirname)(paths.queueTree), `${STAGED_QUEUE_PREFIX}${timestampSlug(now())}-${(0, import_node_crypto11.randomUUID)()}`);
|
|
4107
|
+
(0, import_node_fs11.renameSync)(paths.queueTree, staged);
|
|
4108
|
+
cleanup.stagedQueues = staged;
|
|
4109
|
+
cleanup.report.collectorQueuesRemoved = true;
|
|
4110
|
+
}
|
|
4111
|
+
} catch (error2) {
|
|
4112
|
+
warnings.push(`collector queues: ${errorMessage(error2)}`);
|
|
4113
|
+
}
|
|
4114
|
+
try {
|
|
4115
|
+
if ((0, import_node_fs11.existsSync)(paths.database)) {
|
|
4116
|
+
cleanup.databaseCleared = true;
|
|
4117
|
+
cleanup.report.databaseRows = clear(paths.database).deleted;
|
|
4118
|
+
}
|
|
4119
|
+
} catch (error2) {
|
|
4120
|
+
warnings.push(`hub database: ${errorMessage(error2)}`);
|
|
4121
|
+
}
|
|
4122
|
+
cleanup.report.warning = warnings.length > 0 ? warnings.join("; ") : null;
|
|
4123
|
+
return cleanup;
|
|
4124
|
+
}
|
|
4125
|
+
function undoMachineDataCleanup(paths, stagedQueues) {
|
|
4126
|
+
if (stagedQueues === null || !(0, import_node_fs11.existsSync)(stagedQueues)) return [];
|
|
4127
|
+
try {
|
|
4128
|
+
if ((0, import_node_fs11.existsSync)(paths.queueTree)) {
|
|
4129
|
+
const failedQueue = `${paths.queueTree}.failed-transition-${(0, import_node_crypto11.randomUUID)()}`;
|
|
4130
|
+
(0, import_node_fs11.renameSync)(paths.queueTree, failedQueue);
|
|
4131
|
+
try {
|
|
4132
|
+
(0, import_node_fs11.renameSync)(stagedQueues, paths.queueTree);
|
|
4133
|
+
} catch (error2) {
|
|
4134
|
+
(0, import_node_fs11.renameSync)(failedQueue, paths.queueTree);
|
|
4135
|
+
throw error2;
|
|
4136
|
+
}
|
|
4137
|
+
return [`restored the collector queue tree; replacement runtime queue preserved at ${failedQueue}`];
|
|
4138
|
+
}
|
|
4139
|
+
(0, import_node_fs11.renameSync)(stagedQueues, paths.queueTree);
|
|
4140
|
+
return ["restored the collector queue tree the transition had staged aside"];
|
|
4141
|
+
} catch (error2) {
|
|
4142
|
+
return [`machine data rollback could not restore the collector queue: ${errorMessage(error2)}`];
|
|
4143
|
+
}
|
|
4144
|
+
}
|
|
4145
|
+
function completeMachineDataCleanup(stateRoot, cleanup, release, write) {
|
|
4146
|
+
if (!cleanup.report.transitioned) return;
|
|
4147
|
+
if (cleanup.report.warning !== null) return;
|
|
4148
|
+
try {
|
|
4149
|
+
recordMachineDataTransition(stateRoot, release, write);
|
|
4150
|
+
} catch (error2) {
|
|
4151
|
+
cleanup.report.warning = `could not record transition completion: ${errorMessage(error2)}`;
|
|
4152
|
+
return;
|
|
4153
|
+
}
|
|
4154
|
+
if (cleanup.stagedQueues !== null) {
|
|
4155
|
+
try {
|
|
4156
|
+
(0, import_node_fs11.rmSync)(cleanup.stagedQueues, { recursive: true, force: true });
|
|
4157
|
+
} catch (error2) {
|
|
4158
|
+
cleanup.report.warning = `transition completed; staged queue remains at ${cleanup.stagedQueues}: ${errorMessage(error2)}`;
|
|
4159
|
+
}
|
|
4160
|
+
}
|
|
4161
|
+
}
|
|
4162
|
+
function machineDataReportRows(report) {
|
|
4163
|
+
if (report.databaseRows === null) return null;
|
|
4164
|
+
return Object.values(report.databaseRows).reduce((sum, rows) => sum + rows, 0);
|
|
4165
|
+
}
|
|
4166
|
+
function machineDataKeptNote() {
|
|
4167
|
+
return "accounts, sessions, enrollment and grants, settings, alert rules/jobs/webhook settings, machine names/tags and recordings were kept";
|
|
4168
|
+
}
|
|
4169
|
+
function describeMachineDataReport(report) {
|
|
4170
|
+
const summary = report.transitioned ? (() => {
|
|
4171
|
+
const rows = machineDataReportRows(report);
|
|
4172
|
+
const parts = [
|
|
4173
|
+
rows === null ? "no hub database" : `${rows} database row(s)`,
|
|
4174
|
+
...report.collectorQueuesRemoved ? ["the collector queue tree"] : []
|
|
4175
|
+
];
|
|
4176
|
+
return `Machine data: one-time RAM-first transition discarded ${parts.join(" and ")}. The ${machineDataKeptNote()}.`;
|
|
4177
|
+
})() : "Machine data: one-time transition already completed; durable history and collector queues preserved.";
|
|
4178
|
+
return {
|
|
4179
|
+
summary,
|
|
4180
|
+
warning: report.warning === null ? null : `Machine-data cleanup warning (${report.warning}). The upgrade is healthy; cleanup without a completion marker is retried on the next upgrade.`
|
|
4181
|
+
};
|
|
4182
|
+
}
|
|
3881
4183
|
|
|
3882
4184
|
// src/cli/health.ts
|
|
3883
4185
|
var import_node_http2 = require("node:http");
|
|
@@ -4071,6 +4373,7 @@ function dependencies(deps = {}) {
|
|
|
4071
4373
|
restore: deps.restore ?? restoreDatabase,
|
|
4072
4374
|
inspect: deps.inspect ?? inspectDatabase,
|
|
4073
4375
|
inspectRuntime: deps.inspectRuntime ?? inspectDatabaseWithRuntime,
|
|
4376
|
+
clearHistory: deps.clearHistory ?? clearMachineHistory,
|
|
4074
4377
|
waitHealth: deps.waitHealth ?? waitForHealth,
|
|
4075
4378
|
activate: deps.activate ?? activatePackage,
|
|
4076
4379
|
swap: deps.swap ?? swapRuntimes,
|
|
@@ -4081,10 +4384,10 @@ function dependencies(deps = {}) {
|
|
|
4081
4384
|
function acquireInstallLocks(dir, acquireLease) {
|
|
4082
4385
|
const releases = [];
|
|
4083
4386
|
try {
|
|
4084
|
-
releases.push(acquireLease((0,
|
|
4085
|
-
releases.push(acquireLease((0,
|
|
4086
|
-
releases.push(acquireLease((0,
|
|
4087
|
-
releases.push(acquireLease((0,
|
|
4387
|
+
releases.push(acquireLease((0, import_node_path13.join)(dir, "run", "hub.lock")));
|
|
4388
|
+
releases.push(acquireLease((0, import_node_path13.join)(dir, "run", "collector.lock")));
|
|
4389
|
+
releases.push(acquireLease((0, import_node_path13.join)(dir, "run", "rigscope.lock")));
|
|
4390
|
+
releases.push(acquireLease((0, import_node_path13.join)(dir, "collector", "collector-runtime.lock")));
|
|
4088
4391
|
} catch (error2) {
|
|
4089
4392
|
for (const release of releases.reverse()) {
|
|
4090
4393
|
try {
|
|
@@ -4150,8 +4453,11 @@ function assertComponentsStopped(dir, deps, components) {
|
|
|
4150
4453
|
}
|
|
4151
4454
|
}
|
|
4152
4455
|
}
|
|
4456
|
+
function machineDataPaths(dir) {
|
|
4457
|
+
return { database: databasePath(dir), queueTree: (0, import_node_path13.join)(dir, "collector", "outbox") };
|
|
4458
|
+
}
|
|
4153
4459
|
function collectorStateCheck(dir) {
|
|
4154
|
-
const path2 = (0,
|
|
4460
|
+
const path2 = (0, import_node_path13.join)(dir, "collector", "state.json");
|
|
4155
4461
|
let raw;
|
|
4156
4462
|
try {
|
|
4157
4463
|
raw = readPrivate(path2);
|
|
@@ -4175,13 +4481,13 @@ function hubTarget(config, dir) {
|
|
|
4175
4481
|
role: "hub",
|
|
4176
4482
|
port: config.port,
|
|
4177
4483
|
origin: config.origin,
|
|
4178
|
-
socket: config.socket ?? (0,
|
|
4484
|
+
socket: config.socket ?? (0, import_node_path13.join)(dir, "run", "hub.sock")
|
|
4179
4485
|
});
|
|
4180
4486
|
}
|
|
4181
4487
|
async function verifyRunningInstallation(options) {
|
|
4182
4488
|
const d = dependencies(options.deps);
|
|
4183
4489
|
const deadline = Date.now() + (options.deadlineMs ?? DEFAULT_HEALTH_DEADLINE_MS);
|
|
4184
|
-
const runtime = (0,
|
|
4490
|
+
const runtime = (0, import_node_path13.join)(options.dir, "runtime");
|
|
4185
4491
|
const version = runtimeVersion(runtime);
|
|
4186
4492
|
if (version !== options.expectedVersion) {
|
|
4187
4493
|
throw new OperationsError(
|
|
@@ -4222,7 +4528,7 @@ async function verifyRunningInstallation(options) {
|
|
|
4222
4528
|
}
|
|
4223
4529
|
}
|
|
4224
4530
|
const path2 = databasePath(options.dir);
|
|
4225
|
-
if (!(0,
|
|
4531
|
+
if (!(0, import_node_fs12.existsSync)(path2)) {
|
|
4226
4532
|
if (status.active) {
|
|
4227
4533
|
throw new OperationsError("database-missing", `hub database is missing after activation: ${path2}`);
|
|
4228
4534
|
}
|
|
@@ -4262,8 +4568,8 @@ async function verifyRunningInstallation(options) {
|
|
|
4262
4568
|
let problem = "collector has not sampled";
|
|
4263
4569
|
while (Date.now() < deadline) {
|
|
4264
4570
|
try {
|
|
4265
|
-
const marker = JSON.parse(readPrivate((0,
|
|
4266
|
-
const owner = JSON.parse(readPrivate((0,
|
|
4571
|
+
const marker = JSON.parse(readPrivate((0, import_node_path13.join)(options.dir, "run", "collector-health.json")));
|
|
4572
|
+
const owner = JSON.parse(readPrivate((0, import_node_path13.join)(options.dir, "collector", "collector-runtime.lock")));
|
|
4267
4573
|
if (marker.version !== options.expectedVersion) throw new Error("collector version does not match the activated release");
|
|
4268
4574
|
if (marker.pid !== owner.pid || !Number.isSafeInteger(marker.pid)) throw new Error("collector readiness belongs to another process");
|
|
4269
4575
|
process.kill(marker.pid, 0);
|
|
@@ -4281,7 +4587,7 @@ async function verifyRunningInstallation(options) {
|
|
|
4281
4587
|
return { version, health, database };
|
|
4282
4588
|
}
|
|
4283
4589
|
async function recoverActivation(options) {
|
|
4284
|
-
const runtime = (0,
|
|
4590
|
+
const runtime = (0, import_node_path13.join)(options.dir, "runtime");
|
|
4285
4591
|
const messages = [];
|
|
4286
4592
|
let releaseLocks = null;
|
|
4287
4593
|
try {
|
|
@@ -4290,12 +4596,16 @@ async function recoverActivation(options) {
|
|
|
4290
4596
|
if (status.active) options.deps.service.stop(options.dir, component);
|
|
4291
4597
|
}
|
|
4292
4598
|
assertComponentsStopped(options.dir, options.deps, COMPONENT_LIST);
|
|
4293
|
-
if ((0,
|
|
4599
|
+
if ((0, import_node_fs12.existsSync)(databasePath(options.dir))) assertNoActiveHubLock(databasePath(options.dir));
|
|
4294
4600
|
releaseLocks = acquireInstallLocks(options.dir, options.deps.acquireLease);
|
|
4601
|
+
messages.push(...undoMachineDataCleanup(machineDataPaths(options.dir), options.machineData?.stagedQueues ?? null));
|
|
4602
|
+
if (options.machineData?.report.warning) {
|
|
4603
|
+
messages.push(`machine-data cleanup was incomplete: ${options.machineData.report.warning}`);
|
|
4604
|
+
}
|
|
4295
4605
|
if (options.activated) {
|
|
4296
4606
|
try {
|
|
4297
|
-
if ((0,
|
|
4298
|
-
const restoredVersion = runtimeVersion((0,
|
|
4607
|
+
if ((0, import_node_fs12.existsSync)(runtime)) options.deps.swap(options.dir);
|
|
4608
|
+
const restoredVersion = runtimeVersion((0, import_node_path13.join)(options.dir, "runtime"));
|
|
4299
4609
|
if (restoredVersion !== options.previousVersion) {
|
|
4300
4610
|
throw new Error(`restored runtime reports ${restoredVersion}, expected ${options.previousVersion}`);
|
|
4301
4611
|
}
|
|
@@ -4306,10 +4616,11 @@ async function recoverActivation(options) {
|
|
|
4306
4616
|
}
|
|
4307
4617
|
}
|
|
4308
4618
|
const path2 = databasePath(options.dir);
|
|
4309
|
-
|
|
4619
|
+
const transitionClearedHistory = options.machineData?.databaseCleared === true;
|
|
4620
|
+
if (options.backupPath !== null && (0, import_node_fs12.existsSync)(options.backupPath) && (0, import_node_fs12.existsSync)(path2)) {
|
|
4310
4621
|
try {
|
|
4311
|
-
const old = options.deps.inspectRuntime((0,
|
|
4312
|
-
if (!old.integrityOk || old.newerSchema || old.ledgerProblem !== null) {
|
|
4622
|
+
const old = options.deps.inspectRuntime((0, import_node_path13.join)(options.dir, "runtime"), path2);
|
|
4623
|
+
if (transitionClearedHistory || !old.integrityOk || old.newerSchema || old.ledgerProblem !== null) {
|
|
4313
4624
|
const restored = await options.deps.restore({
|
|
4314
4625
|
input: options.backupPath,
|
|
4315
4626
|
database: path2,
|
|
@@ -4326,16 +4637,16 @@ async function recoverActivation(options) {
|
|
|
4326
4637
|
messages.push(`database recovery failed: ${errorMessage(error2)}; pre-upgrade copy is ${options.backupPath}`);
|
|
4327
4638
|
return messages.join("; ");
|
|
4328
4639
|
}
|
|
4329
|
-
} else if (options.backupPath === null && (0,
|
|
4640
|
+
} else if (options.backupPath === null && (0, import_node_fs12.existsSync)(path2)) {
|
|
4330
4641
|
try {
|
|
4331
|
-
const old = options.deps.inspectRuntime((0,
|
|
4642
|
+
const old = options.deps.inspectRuntime((0, import_node_path13.join)(options.dir, "runtime"), path2);
|
|
4332
4643
|
if (!old.integrityOk || old.newerSchema || old.ledgerProblem !== null) {
|
|
4333
|
-
const backups = (0,
|
|
4644
|
+
const backups = (0, import_node_path13.join)(options.dir, "backups");
|
|
4334
4645
|
ensurePrivateDir(backups);
|
|
4335
|
-
const preserved = (0,
|
|
4336
|
-
(0,
|
|
4646
|
+
const preserved = (0, import_node_path13.join)(backups, `failed-activation-${timestampSlug(options.deps.now())}.sqlite`);
|
|
4647
|
+
(0, import_node_fs12.renameSync)(path2, preserved);
|
|
4337
4648
|
for (const sidecar of [`${path2}-wal`, `${path2}-shm`]) {
|
|
4338
|
-
if ((0,
|
|
4649
|
+
if ((0, import_node_fs12.existsSync)(sidecar)) (0, import_node_fs12.renameSync)(sidecar, `${preserved}${sidecar.slice(path2.length)}`);
|
|
4339
4650
|
}
|
|
4340
4651
|
messages.push(`preserved the failed activation database at ${preserved}; the previous runtime will create a fresh database`);
|
|
4341
4652
|
} else {
|
|
@@ -4379,8 +4690,8 @@ async function upgradeInstallation(options, injected = {}) {
|
|
|
4379
4690
|
const deps = dependencies(injected);
|
|
4380
4691
|
const config = readSetup(options.dir);
|
|
4381
4692
|
if (!config) throw new OperationsError("not-installed", "No installation found. Run rigscope install first.");
|
|
4382
|
-
const runtime = (0,
|
|
4383
|
-
if (!(0,
|
|
4693
|
+
const runtime = (0, import_node_path13.join)(options.dir, "runtime");
|
|
4694
|
+
if (!(0, import_node_fs12.existsSync)(runtime)) {
|
|
4384
4695
|
throw new OperationsError("not-installed", "Install a managed runtime before upgrading.");
|
|
4385
4696
|
}
|
|
4386
4697
|
const currentVersion = runtimeVersion(runtime);
|
|
@@ -4393,7 +4704,7 @@ async function upgradeInstallation(options, injected = {}) {
|
|
|
4393
4704
|
expectedVersion = runtimeVersion(stage);
|
|
4394
4705
|
assertRuntimeArtifacts(stage, "staged runtime");
|
|
4395
4706
|
const path2 = databasePath(options.dir);
|
|
4396
|
-
if ((0,
|
|
4707
|
+
if ((0, import_node_fs12.existsSync)(path2)) {
|
|
4397
4708
|
const staged = deps.inspectRuntime(stage, path2);
|
|
4398
4709
|
if (!staged.integrityOk) {
|
|
4399
4710
|
throw new OperationsError("database-integrity", `database integrity check failed before upgrade: ${path2}`);
|
|
@@ -4410,26 +4721,27 @@ async function upgradeInstallation(options, injected = {}) {
|
|
|
4410
4721
|
expectedSchema = staged.supportedSchemaVersion;
|
|
4411
4722
|
}
|
|
4412
4723
|
} catch (error2) {
|
|
4413
|
-
(0,
|
|
4724
|
+
(0, import_node_fs12.rmSync)(stage, { recursive: true, force: true });
|
|
4414
4725
|
throw error2;
|
|
4415
4726
|
}
|
|
4416
4727
|
const snapshot = snapshotComponents(options.dir, deps);
|
|
4417
4728
|
const running = snapshot.running;
|
|
4418
4729
|
let releaseLocks = null;
|
|
4419
|
-
const releaseOperation = deps.acquireLease((0,
|
|
4730
|
+
const releaseOperation = deps.acquireLease((0, import_node_path13.join)(options.dir, "run", "operation.lock"));
|
|
4420
4731
|
let backupPath = null;
|
|
4421
4732
|
let activated = false;
|
|
4733
|
+
let machineData = null;
|
|
4422
4734
|
try {
|
|
4423
4735
|
stopComponents(options.dir, deps, running);
|
|
4424
4736
|
assertComponentsStopped(options.dir, deps, running);
|
|
4425
|
-
if (running.includes("hub") || componentEnabled(config, "hub") || (0,
|
|
4737
|
+
if (running.includes("hub") || componentEnabled(config, "hub") || (0, import_node_fs12.existsSync)(databasePath(options.dir))) {
|
|
4426
4738
|
assertNoActiveHubLock(databasePath(options.dir));
|
|
4427
4739
|
}
|
|
4428
4740
|
releaseLocks = acquireInstallLocks(options.dir, deps.acquireLease);
|
|
4429
|
-
if ((0,
|
|
4430
|
-
const backups = (0,
|
|
4741
|
+
if ((0, import_node_fs12.existsSync)(databasePath(options.dir))) {
|
|
4742
|
+
const backups = (0, import_node_path13.join)(options.dir, "backups");
|
|
4431
4743
|
ensurePrivateDir(backups);
|
|
4432
|
-
backupPath = (0,
|
|
4744
|
+
backupPath = (0, import_node_path13.join)(
|
|
4433
4745
|
backups,
|
|
4434
4746
|
`pre-upgrade-${currentVersion}-to-${expectedVersion}-${timestampSlug(deps.now())}.sqlite`
|
|
4435
4747
|
);
|
|
@@ -4458,6 +4770,9 @@ async function upgradeInstallation(options, injected = {}) {
|
|
|
4458
4770
|
}
|
|
4459
4771
|
deps.activate(options.dir, stage);
|
|
4460
4772
|
activated = true;
|
|
4773
|
+
machineData = performMachineDataCleanup(options.dir, machineDataPaths(options.dir), deps.now, {
|
|
4774
|
+
clear: deps.clearHistory
|
|
4775
|
+
});
|
|
4461
4776
|
releaseLocks();
|
|
4462
4777
|
releaseLocks = null;
|
|
4463
4778
|
for (const component of running) deps.service.start(options.dir, component);
|
|
@@ -4473,7 +4788,7 @@ async function upgradeInstallation(options, injected = {}) {
|
|
|
4473
4788
|
});
|
|
4474
4789
|
restoreStartup(options.dir, deps, snapshot.enabled, false);
|
|
4475
4790
|
const now = new Date(deps.now()).toISOString();
|
|
4476
|
-
if (backupPath !== null && (0,
|
|
4791
|
+
if (backupPath !== null && (0, import_node_fs12.existsSync)(backupPath)) {
|
|
4477
4792
|
const info = deps.inspect(backupPath);
|
|
4478
4793
|
const record = {
|
|
4479
4794
|
path: backupPath,
|
|
@@ -4497,13 +4812,15 @@ async function upgradeInstallation(options, injected = {}) {
|
|
|
4497
4812
|
activatedAt: now
|
|
4498
4813
|
}
|
|
4499
4814
|
});
|
|
4815
|
+
completeMachineDataCleanup(options.dir, machineData, expectedVersion);
|
|
4500
4816
|
return {
|
|
4501
4817
|
version: expectedVersion,
|
|
4502
4818
|
previousVersion: currentVersion,
|
|
4503
4819
|
backupPath,
|
|
4504
4820
|
schemaVersion: verification.database?.schemaVersion ?? expectedSchema,
|
|
4505
4821
|
serviceRestarted: running.length > 0,
|
|
4506
|
-
verification
|
|
4822
|
+
verification,
|
|
4823
|
+
machineHistory: machineData.report
|
|
4507
4824
|
};
|
|
4508
4825
|
} catch (error2) {
|
|
4509
4826
|
releaseLocks?.();
|
|
@@ -4513,6 +4830,7 @@ async function upgradeInstallation(options, injected = {}) {
|
|
|
4513
4830
|
config,
|
|
4514
4831
|
previousVersion: currentVersion,
|
|
4515
4832
|
backupPath,
|
|
4833
|
+
machineData,
|
|
4516
4834
|
running,
|
|
4517
4835
|
startup: snapshot.enabled,
|
|
4518
4836
|
activated,
|
|
@@ -4526,13 +4844,13 @@ async function upgradeInstallation(options, injected = {}) {
|
|
|
4526
4844
|
} finally {
|
|
4527
4845
|
releaseLocks?.();
|
|
4528
4846
|
releaseOperation();
|
|
4529
|
-
if ((0,
|
|
4847
|
+
if ((0, import_node_fs12.existsSync)(stage)) (0, import_node_fs12.rmSync)(stage, { recursive: true, force: true });
|
|
4530
4848
|
}
|
|
4531
4849
|
}
|
|
4532
4850
|
function rollbackBackup(options) {
|
|
4533
4851
|
if (options.explicitBackup !== void 0) {
|
|
4534
4852
|
const path2 = options.explicitBackup;
|
|
4535
|
-
if (!(0,
|
|
4853
|
+
if (!(0, import_node_fs12.existsSync)(path2)) {
|
|
4536
4854
|
throw new OperationsError("backup-missing", `rollback backup does not exist: ${path2}`);
|
|
4537
4855
|
}
|
|
4538
4856
|
const info2 = options.deps.inspect(path2);
|
|
@@ -4551,7 +4869,7 @@ function rollbackBackup(options) {
|
|
|
4551
4869
|
`database schema ${options.previousSupport.schemaVersion} is newer than previous runtime ${options.previousVersion} (schema ${options.previousSupport.supportedSchemaVersion}); no paired pre-upgrade backup is recorded for ${options.currentVersion}. Re-run with --backup PATH naming a copy that matches schema ${options.previousSupport.supportedSchemaVersion} or older`
|
|
4552
4870
|
);
|
|
4553
4871
|
}
|
|
4554
|
-
if (!(0,
|
|
4872
|
+
if (!(0, import_node_fs12.existsSync)(recorded.path)) {
|
|
4555
4873
|
throw new OperationsError(
|
|
4556
4874
|
"backup-missing",
|
|
4557
4875
|
`paired pre-upgrade backup for ${options.currentVersion} is missing: ${recorded.path}`
|
|
@@ -4573,10 +4891,10 @@ async function rollbackInstallation(options, injected = {}) {
|
|
|
4573
4891
|
const deps = dependencies(injected);
|
|
4574
4892
|
const config = readSetup(options.dir);
|
|
4575
4893
|
if (!config) throw new OperationsError("not-installed", "No installation found. Run rigscope install first.");
|
|
4576
|
-
const runtime = (0,
|
|
4577
|
-
const previousRuntime = (0,
|
|
4578
|
-
if (!(0,
|
|
4579
|
-
if (!(0,
|
|
4894
|
+
const runtime = (0, import_node_path13.join)(options.dir, "runtime");
|
|
4895
|
+
const previousRuntime = (0, import_node_path13.join)(options.dir, "runtime-previous");
|
|
4896
|
+
if (!(0, import_node_fs12.existsSync)(runtime)) throw new OperationsError("not-installed", "No active runtime is installed.");
|
|
4897
|
+
if (!(0, import_node_fs12.existsSync)(previousRuntime)) {
|
|
4580
4898
|
throw new OperationsError("no-previous-release", "No previous runtime is available for rollback.");
|
|
4581
4899
|
}
|
|
4582
4900
|
const currentVersion = runtimeVersion(runtime);
|
|
@@ -4587,19 +4905,19 @@ async function rollbackInstallation(options, injected = {}) {
|
|
|
4587
4905
|
const snapshot = snapshotComponents(options.dir, deps);
|
|
4588
4906
|
const running = snapshot.running;
|
|
4589
4907
|
let releaseLocks = null;
|
|
4590
|
-
const releaseOperation = deps.acquireLease((0,
|
|
4908
|
+
const releaseOperation = deps.acquireLease((0, import_node_path13.join)(options.dir, "run", "operation.lock"));
|
|
4591
4909
|
let restoredBackup = null;
|
|
4592
4910
|
let preRestoreBackup = null;
|
|
4593
4911
|
let swapped = false;
|
|
4594
4912
|
try {
|
|
4595
4913
|
stopComponents(options.dir, deps, running);
|
|
4596
4914
|
assertComponentsStopped(options.dir, deps, running);
|
|
4597
|
-
if (running.includes("hub") || componentEnabled(config, "hub") || (0,
|
|
4915
|
+
if (running.includes("hub") || componentEnabled(config, "hub") || (0, import_node_fs12.existsSync)(databasePath(options.dir))) {
|
|
4598
4916
|
assertNoActiveHubLock(databasePath(options.dir));
|
|
4599
4917
|
}
|
|
4600
4918
|
releaseLocks = acquireInstallLocks(options.dir, deps.acquireLease);
|
|
4601
4919
|
const path2 = databasePath(options.dir);
|
|
4602
|
-
if ((0,
|
|
4920
|
+
if ((0, import_node_fs12.existsSync)(path2)) {
|
|
4603
4921
|
const previousSupport = deps.inspectRuntime(previousRuntime, path2);
|
|
4604
4922
|
if (!previousSupport.integrityOk || previousSupport.newerSchema || previousSupport.ledgerProblem !== null) {
|
|
4605
4923
|
const backup3 = rollbackBackup({
|
|
@@ -4670,7 +4988,7 @@ async function rollbackInstallation(options, injected = {}) {
|
|
|
4670
4988
|
if (status.active) deps.service.stop(options.dir, component);
|
|
4671
4989
|
}
|
|
4672
4990
|
assertComponentsStopped(options.dir, deps, COMPONENT_LIST);
|
|
4673
|
-
if ((0,
|
|
4991
|
+
if ((0, import_node_fs12.existsSync)(databasePath(options.dir))) assertNoActiveHubLock(databasePath(options.dir));
|
|
4674
4992
|
releaseLocks = acquireInstallLocks(options.dir, deps.acquireLease);
|
|
4675
4993
|
} catch (stopError) {
|
|
4676
4994
|
throw new OperationsError("rollback-failed", `rollback failed: ${errorMessage(error2)}. Recovery refused while runtime ownership is uncertain: ${errorMessage(stopError)}`, { cause: error2 });
|
|
@@ -4684,7 +5002,7 @@ async function rollbackInstallation(options, injected = {}) {
|
|
|
4684
5002
|
safeToRestart = false;
|
|
4685
5003
|
}
|
|
4686
5004
|
}
|
|
4687
|
-
if (preRestoreBackup !== null && (0,
|
|
5005
|
+
if (preRestoreBackup !== null && (0, import_node_fs12.existsSync)(preRestoreBackup)) {
|
|
4688
5006
|
try {
|
|
4689
5007
|
await deps.restore({
|
|
4690
5008
|
input: preRestoreBackup,
|
|
@@ -4699,7 +5017,7 @@ async function rollbackInstallation(options, injected = {}) {
|
|
|
4699
5017
|
safeToRestart = false;
|
|
4700
5018
|
}
|
|
4701
5019
|
}
|
|
4702
|
-
if (safeToRestart && running.includes("hub") && (0,
|
|
5020
|
+
if (safeToRestart && running.includes("hub") && (0, import_node_fs12.existsSync)(databasePath(options.dir))) {
|
|
4703
5021
|
try {
|
|
4704
5022
|
const info = deps.inspectRuntime(runtime, databasePath(options.dir));
|
|
4705
5023
|
if (!info.integrityOk || info.newerSchema || info.ledgerProblem !== null) throw new Error("runtime/database compatibility is not established");
|
|
@@ -4746,17 +5064,17 @@ async function rollbackInstallation(options, injected = {}) {
|
|
|
4746
5064
|
|
|
4747
5065
|
// src/cli/lifecycle.ts
|
|
4748
5066
|
function collectorEnrolled(dir) {
|
|
4749
|
-
const path2 = (0,
|
|
4750
|
-
if (!(0,
|
|
5067
|
+
const path2 = (0, import_node_path14.join)(dir, "collector", "state.json");
|
|
5068
|
+
if (!(0, import_node_fs13.existsSync)(path2)) return false;
|
|
4751
5069
|
const state = JSON.parse(readPrivate(path2));
|
|
4752
5070
|
return Array.isArray(state.destinations) && state.destinations.length > 0;
|
|
4753
5071
|
}
|
|
4754
5072
|
var AWAITING_CONNECTION = "Collector is awaiting connection. Run rigscope connect https://your-hub first.";
|
|
4755
5073
|
function assertNoCompetingRuntime(dir, component) {
|
|
4756
5074
|
const locks = [
|
|
4757
|
-
(0,
|
|
4758
|
-
(0,
|
|
4759
|
-
...component === "collector" ? [(0,
|
|
5075
|
+
(0, import_node_path14.join)(dir, "run", component === "hub" ? "hub.lock" : "collector.lock"),
|
|
5076
|
+
(0, import_node_path14.join)(dir, "run", "rigscope.lock"),
|
|
5077
|
+
...component === "collector" ? [(0, import_node_path14.join)(dir, "collector", "collector-runtime.lock")] : []
|
|
4760
5078
|
];
|
|
4761
5079
|
const releases = [];
|
|
4762
5080
|
try {
|
|
@@ -4775,11 +5093,11 @@ function assertNoCompetingRuntime(dir, component) {
|
|
|
4775
5093
|
async function startInstallation(dir, component, injected = {}) {
|
|
4776
5094
|
const config = readSetup(dir);
|
|
4777
5095
|
if (!config) throw new Error("No background service installed. Run rigscope install first.");
|
|
4778
|
-
if (!(0,
|
|
5096
|
+
if (!(0, import_node_fs13.existsSync)((0, import_node_path14.join)(dir, "runtime"))) throw new Error("No background service installed. Run rigscope install first.");
|
|
4779
5097
|
const selected = component ? [component] : enabledComponents(config);
|
|
4780
5098
|
if (selected.length === 0) throw new Error("No enabled components. Run rigscope enable hub or rigscope enable collector.");
|
|
4781
5099
|
for (const target of selected) {
|
|
4782
|
-
if (!(0,
|
|
5100
|
+
if (!(0, import_node_fs13.existsSync)(unitPath(dir, target))) throw new Error("No background service installed. Run rigscope install first.");
|
|
4783
5101
|
}
|
|
4784
5102
|
const status = injected.status ?? serviceStatus;
|
|
4785
5103
|
const start = injected.start ?? systemctl;
|
|
@@ -4807,7 +5125,7 @@ async function startInstallation(dir, component, injected = {}) {
|
|
|
4807
5125
|
await (injected.verify ?? verifyRunningInstallation)({
|
|
4808
5126
|
dir,
|
|
4809
5127
|
config,
|
|
4810
|
-
expectedVersion: runtimeVersion((0,
|
|
5128
|
+
expectedVersion: runtimeVersion((0, import_node_path14.join)(dir, "runtime")),
|
|
4811
5129
|
components: started,
|
|
4812
5130
|
requireActive: started
|
|
4813
5131
|
});
|
|
@@ -4891,11 +5209,11 @@ function printHelp(message, options = {}) {
|
|
|
4891
5209
|
|
|
4892
5210
|
// src/cli/mutation.ts
|
|
4893
5211
|
async function resumeComponent(dir, component) {
|
|
4894
|
-
if ((0,
|
|
4895
|
-
const run = (0,
|
|
4896
|
-
(0,
|
|
4897
|
-
const log = (0,
|
|
4898
|
-
const fd = (0,
|
|
5212
|
+
if ((0, import_node_fs14.existsSync)((0, import_node_path15.join)(dir, "runtime"))) return startInstallation(dir, component);
|
|
5213
|
+
const run = (0, import_node_path15.join)(dir, "run");
|
|
5214
|
+
(0, import_node_fs14.mkdirSync)(run, { recursive: true, mode: 448 });
|
|
5215
|
+
const log = (0, import_node_path15.join)(run, `${component}.log`);
|
|
5216
|
+
const fd = (0, import_node_fs14.openSync)(log, "a", 384);
|
|
4899
5217
|
let child;
|
|
4900
5218
|
try {
|
|
4901
5219
|
child = (0, import_node_child_process3.spawn)(process.execPath, [process.argv[1], "run", component, "--state-dir", dir], {
|
|
@@ -4904,7 +5222,7 @@ async function resumeComponent(dir, component) {
|
|
|
4904
5222
|
env: process.env
|
|
4905
5223
|
});
|
|
4906
5224
|
} finally {
|
|
4907
|
-
(0,
|
|
5225
|
+
(0, import_node_fs14.closeSync)(fd);
|
|
4908
5226
|
}
|
|
4909
5227
|
let failure;
|
|
4910
5228
|
child.on("error", (error2) => {
|
|
@@ -4915,7 +5233,7 @@ async function resumeComponent(dir, component) {
|
|
|
4915
5233
|
while (Date.now() < deadline) {
|
|
4916
5234
|
if (failure || child.exitCode !== null || child.signalCode !== null) break;
|
|
4917
5235
|
try {
|
|
4918
|
-
const owner = JSON.parse((0,
|
|
5236
|
+
const owner = JSON.parse((0, import_node_fs14.readFileSync)((0, import_node_path15.join)(run, `${component}.lock`), "utf8"));
|
|
4919
5237
|
if (owner.pid === child.pid) return "started";
|
|
4920
5238
|
} catch {
|
|
4921
5239
|
}
|
|
@@ -4971,12 +5289,20 @@ async function prepareMutation(dir, selected, options, deps = {}) {
|
|
|
4971
5289
|
|
|
4972
5290
|
// src/cli/runtime.ts
|
|
4973
5291
|
var import_node_child_process4 = require("node:child_process");
|
|
4974
|
-
var
|
|
5292
|
+
var import_node_path16 = require("node:path");
|
|
5293
|
+
function collectorQueueModeEnvironment(env) {
|
|
5294
|
+
const raw = env["COLLECTOR_QUEUE_MODE"]?.trim();
|
|
5295
|
+
if (raw === void 0 || raw === "") return {};
|
|
5296
|
+
const issues = [];
|
|
5297
|
+
const queueMode = parseQueueMode(env, issues);
|
|
5298
|
+
if (issues.length > 0) throw new Error(issues.join("\n"));
|
|
5299
|
+
return { COLLECTOR_QUEUE_MODE: queueMode };
|
|
5300
|
+
}
|
|
4975
5301
|
function componentLeasePath(dir, component) {
|
|
4976
|
-
return (0,
|
|
5302
|
+
return (0, import_node_path16.join)(dir, "run", `${component}.lock`);
|
|
4977
5303
|
}
|
|
4978
5304
|
function combinedLeasePath(dir) {
|
|
4979
|
-
return (0,
|
|
5305
|
+
return (0, import_node_path16.join)(dir, "run", "rigscope.lock");
|
|
4980
5306
|
}
|
|
4981
5307
|
function label(component) {
|
|
4982
5308
|
return component === "hub" ? "Hub" : "Collector";
|
|
@@ -4993,6 +5319,7 @@ async function runInstallation(root, dir, component) {
|
|
|
4993
5319
|
console.error("No components are enabled. Run rigscope enable hub or rigscope enable collector.");
|
|
4994
5320
|
return 0;
|
|
4995
5321
|
}
|
|
5322
|
+
const collectorEnvironment = selected.includes("collector") ? collectorQueueModeEnvironment(process.env) : {};
|
|
4996
5323
|
if (selected.includes("collector") && !collectorHasDestinations(dir)) {
|
|
4997
5324
|
console.log("Collector awaiting connection. Run rigscope connect https://your-hub.");
|
|
4998
5325
|
const remaining = selected.filter((role) => role !== "collector");
|
|
@@ -5032,13 +5359,14 @@ async function runInstallation(root, dir, component) {
|
|
|
5032
5359
|
process.on("SIGTERM", signal);
|
|
5033
5360
|
process.on("SIGINT", signal);
|
|
5034
5361
|
function launch(role) {
|
|
5035
|
-
const child = (0, import_node_child_process4.spawn)(process.execPath, [(0,
|
|
5362
|
+
const child = (0, import_node_child_process4.spawn)(process.execPath, [(0, import_node_path16.join)(root, "dist", `${role}.cjs`)], { cwd: root, stdio: "inherit", env: {
|
|
5036
5363
|
...environment,
|
|
5037
5364
|
NODE_ENV: "production",
|
|
5038
5365
|
...role === "hub" ? hubEnvironment(dir, config) : {
|
|
5039
5366
|
COLLECTOR_MODE: "real",
|
|
5040
|
-
COLLECTOR_STATE_FILE: (0,
|
|
5041
|
-
COLLECTOR_HEALTH_FILE: (0,
|
|
5367
|
+
COLLECTOR_STATE_FILE: (0, import_node_path16.join)(dir, "collector", "state.json"),
|
|
5368
|
+
COLLECTOR_HEALTH_FILE: (0, import_node_path16.join)(dir, "run", "collector-health.json"),
|
|
5369
|
+
...collectorEnvironment
|
|
5042
5370
|
}
|
|
5043
5371
|
} });
|
|
5044
5372
|
children.add(child);
|
|
@@ -5065,8 +5393,8 @@ async function runInstallation(root, dir, component) {
|
|
|
5065
5393
|
}
|
|
5066
5394
|
|
|
5067
5395
|
// src/cli/doctor.ts
|
|
5068
|
-
var
|
|
5069
|
-
var
|
|
5396
|
+
var import_node_fs15 = require("node:fs");
|
|
5397
|
+
var import_node_path17 = require("node:path");
|
|
5070
5398
|
var DEFAULT_DEPENDENCIES = {
|
|
5071
5399
|
serviceStatus,
|
|
5072
5400
|
probeHealth,
|
|
@@ -5076,7 +5404,7 @@ var DEFAULT_DEPENDENCIES = {
|
|
|
5076
5404
|
inspectDatabase,
|
|
5077
5405
|
diskFree: (path2) => {
|
|
5078
5406
|
try {
|
|
5079
|
-
const stats = (0,
|
|
5407
|
+
const stats = (0, import_node_fs15.statfsSync)(path2);
|
|
5080
5408
|
return { free: Number(stats.bavail) * Number(stats.bsize), total: Number(stats.blocks) * Number(stats.bsize) };
|
|
5081
5409
|
} catch {
|
|
5082
5410
|
return null;
|
|
@@ -5085,13 +5413,13 @@ var DEFAULT_DEPENDENCIES = {
|
|
|
5085
5413
|
sensorReadable: (paths) => paths.filter((path2) => {
|
|
5086
5414
|
let fd;
|
|
5087
5415
|
try {
|
|
5088
|
-
fd = (0,
|
|
5089
|
-
(0,
|
|
5416
|
+
fd = (0, import_node_fs15.openSync)(path2, "r");
|
|
5417
|
+
(0, import_node_fs15.readSync)(fd, Buffer.alloc(1), 0, 1, 0);
|
|
5090
5418
|
return true;
|
|
5091
5419
|
} catch {
|
|
5092
5420
|
return false;
|
|
5093
5421
|
} finally {
|
|
5094
|
-
if (fd !== void 0) (0,
|
|
5422
|
+
if (fd !== void 0) (0, import_node_fs15.closeSync)(fd);
|
|
5095
5423
|
}
|
|
5096
5424
|
})
|
|
5097
5425
|
};
|
|
@@ -5153,10 +5481,10 @@ async function diagnoseInstallation(dir, injected = {}) {
|
|
|
5153
5481
|
}
|
|
5154
5482
|
for (const [id, label3, path2] of [
|
|
5155
5483
|
["state-dir", "State directory", dir],
|
|
5156
|
-
["config-mode", "Configuration permissions", (0,
|
|
5484
|
+
["config-mode", "Configuration permissions", (0, import_node_path17.join)(dir, "config.json")]
|
|
5157
5485
|
]) {
|
|
5158
5486
|
try {
|
|
5159
|
-
const stat = (0,
|
|
5487
|
+
const stat = (0, import_node_fs15.lstatSync)(path2);
|
|
5160
5488
|
const privateEntry = id === "state-dir" ? stat.isDirectory() : stat.isFile();
|
|
5161
5489
|
const privateMode = (stat.mode & 63) === 0;
|
|
5162
5490
|
add({
|
|
@@ -5171,7 +5499,7 @@ async function diagnoseInstallation(dir, injected = {}) {
|
|
|
5171
5499
|
}
|
|
5172
5500
|
}
|
|
5173
5501
|
let runtime = null;
|
|
5174
|
-
if (!(0,
|
|
5502
|
+
if (!(0, import_node_fs15.existsSync)((0, import_node_path17.join)(dir, "runtime"))) {
|
|
5175
5503
|
add({
|
|
5176
5504
|
id: "runtime",
|
|
5177
5505
|
label: "Runtime",
|
|
@@ -5181,9 +5509,9 @@ async function diagnoseInstallation(dir, injected = {}) {
|
|
|
5181
5509
|
});
|
|
5182
5510
|
} else {
|
|
5183
5511
|
try {
|
|
5184
|
-
assertRuntimeArtifacts((0,
|
|
5185
|
-
const version2 = runtimeVersion((0,
|
|
5186
|
-
runtime = (0,
|
|
5512
|
+
assertRuntimeArtifacts((0, import_node_path17.join)(dir, "runtime"), "runtime");
|
|
5513
|
+
const version2 = runtimeVersion((0, import_node_path17.join)(dir, "runtime"));
|
|
5514
|
+
runtime = (0, import_node_path17.join)(dir, "runtime");
|
|
5187
5515
|
add({ id: "runtime", label: "Runtime", status: "ok", detail: `rigscope ${version2}` });
|
|
5188
5516
|
} catch (error2) {
|
|
5189
5517
|
add({
|
|
@@ -5195,9 +5523,9 @@ async function diagnoseInstallation(dir, injected = {}) {
|
|
|
5195
5523
|
});
|
|
5196
5524
|
}
|
|
5197
5525
|
}
|
|
5198
|
-
if ((0,
|
|
5526
|
+
if ((0, import_node_fs15.existsSync)((0, import_node_path17.join)(dir, "runtime-previous"))) {
|
|
5199
5527
|
try {
|
|
5200
|
-
add({ id: "previous-runtime", label: "Previous runtime", status: "ok", detail: `rigscope ${runtimeVersion((0,
|
|
5528
|
+
add({ id: "previous-runtime", label: "Previous runtime", status: "ok", detail: `rigscope ${runtimeVersion((0, import_node_path17.join)(dir, "runtime-previous"))}` });
|
|
5201
5529
|
} catch (error2) {
|
|
5202
5530
|
add({ id: "previous-runtime", label: "Previous runtime", status: "warn", detail: errorText2(error2) });
|
|
5203
5531
|
}
|
|
@@ -5259,7 +5587,7 @@ async function diagnoseInstallation(dir, injected = {}) {
|
|
|
5259
5587
|
const collectorActive = services.collector.active;
|
|
5260
5588
|
if (hubEnabled || hubActive) {
|
|
5261
5589
|
const path2 = databasePath(dir);
|
|
5262
|
-
if (!(0,
|
|
5590
|
+
if (!(0, import_node_fs15.existsSync)(path2)) {
|
|
5263
5591
|
add({
|
|
5264
5592
|
id: "database",
|
|
5265
5593
|
label: "Database",
|
|
@@ -5288,7 +5616,7 @@ async function diagnoseInstallation(dir, injected = {}) {
|
|
|
5288
5616
|
});
|
|
5289
5617
|
}
|
|
5290
5618
|
}
|
|
5291
|
-
const space = deps.diskFree((0,
|
|
5619
|
+
const space = deps.diskFree((0, import_node_path17.join)(dir, "hub"));
|
|
5292
5620
|
if (space !== null) {
|
|
5293
5621
|
const free = space.free;
|
|
5294
5622
|
add({
|
|
@@ -5302,9 +5630,9 @@ async function diagnoseInstallation(dir, injected = {}) {
|
|
|
5302
5630
|
}
|
|
5303
5631
|
if (hubEnabled || hubActive) {
|
|
5304
5632
|
if (config.origin) {
|
|
5305
|
-
const socket = config.socket ?? (0,
|
|
5633
|
+
const socket = config.socket ?? (0, import_node_path17.join)(dir, "run", "hub.sock");
|
|
5306
5634
|
try {
|
|
5307
|
-
const stat = (0,
|
|
5635
|
+
const stat = (0, import_node_fs15.lstatSync)(socket);
|
|
5308
5636
|
add({
|
|
5309
5637
|
id: "socket",
|
|
5310
5638
|
label: "Unix socket",
|
|
@@ -5346,7 +5674,7 @@ async function diagnoseInstallation(dir, injected = {}) {
|
|
|
5346
5674
|
}
|
|
5347
5675
|
if (hubActive) {
|
|
5348
5676
|
try {
|
|
5349
|
-
const target = healthTarget({ component: "hub", port: config.port, origin: config.origin, socket: config.socket ?? (0,
|
|
5677
|
+
const target = healthTarget({ component: "hub", port: config.port, origin: config.origin, socket: config.socket ?? (0, import_node_path17.join)(dir, "run", "hub.sock") });
|
|
5350
5678
|
const health = await deps.probeHealth(target, 3e3);
|
|
5351
5679
|
const expected = runtime ? runtimeVersion(runtime) : null;
|
|
5352
5680
|
const reported = typeof health.body?.version === "string" ? health.body.version : null;
|
|
@@ -5364,7 +5692,7 @@ async function diagnoseInstallation(dir, injected = {}) {
|
|
|
5364
5692
|
}
|
|
5365
5693
|
}
|
|
5366
5694
|
if (collectorEnabled || collectorActive) {
|
|
5367
|
-
const statePath = (0,
|
|
5695
|
+
const statePath = (0, import_node_path17.join)(dir, "collector", "state.json");
|
|
5368
5696
|
try {
|
|
5369
5697
|
const raw = readPrivate(statePath);
|
|
5370
5698
|
const state = JSON.parse(raw);
|
|
@@ -5439,17 +5767,17 @@ async function diagnoseInstallation(dir, injected = {}) {
|
|
|
5439
5767
|
function hubEnvironment2(dir, config) {
|
|
5440
5768
|
return {
|
|
5441
5769
|
...!config.origin ? { HUB_HOST: "127.0.0.1", HUB_PORT: String(config.port) } : {},
|
|
5442
|
-
HUB_STATE_FILE: (0,
|
|
5770
|
+
HUB_STATE_FILE: (0, import_node_path17.join)(dir, "hub", "enrollment.json"),
|
|
5443
5771
|
HUB_DATABASE_PATH: databasePath(dir),
|
|
5444
5772
|
HUB_BROWSER_USERS: JSON.stringify(config.users),
|
|
5445
5773
|
HUB_COLLECTORS: JSON.stringify(config.collectors),
|
|
5446
5774
|
...config.maxCollectorConnections === void 0 ? {} : { HUB_MAX_COLLECTOR_CONNECTIONS: String(config.maxCollectorConnections) },
|
|
5447
|
-
...config.origin ? { HUB_PUBLIC_ORIGIN: config.origin, HUB_SOCKET_PATH: config.socket ?? (0,
|
|
5775
|
+
...config.origin ? { HUB_PUBLIC_ORIGIN: config.origin, HUB_SOCKET_PATH: config.socket ?? (0, import_node_path17.join)(dir, "run", "hub.sock") } : {}
|
|
5448
5776
|
};
|
|
5449
5777
|
}
|
|
5450
5778
|
function collectorAwaiting(dir) {
|
|
5451
5779
|
try {
|
|
5452
|
-
const state = JSON.parse(readPrivate((0,
|
|
5780
|
+
const state = JSON.parse(readPrivate((0, import_node_path17.join)(dir, "collector", "state.json")));
|
|
5453
5781
|
return !Array.isArray(state.destinations) || state.destinations.length === 0;
|
|
5454
5782
|
} catch (error2) {
|
|
5455
5783
|
return error2.code === "ENOENT";
|
|
@@ -5461,13 +5789,13 @@ function powerCounterPaths() {
|
|
|
5461
5789
|
if (depth > 3 || paths.length >= 64) return;
|
|
5462
5790
|
let entries;
|
|
5463
5791
|
try {
|
|
5464
|
-
entries = (0,
|
|
5792
|
+
entries = (0, import_node_fs15.readdirSync)(directory, { withFileTypes: true });
|
|
5465
5793
|
} catch {
|
|
5466
5794
|
return;
|
|
5467
5795
|
}
|
|
5468
5796
|
for (const entry2 of entries) {
|
|
5469
5797
|
if (paths.length >= 64) return;
|
|
5470
|
-
const path2 = (0,
|
|
5798
|
+
const path2 = (0, import_node_path17.join)(directory, entry2.name);
|
|
5471
5799
|
if (entry2.name === "energy_uj") {
|
|
5472
5800
|
paths.push(path2);
|
|
5473
5801
|
continue;
|
|
@@ -5511,8 +5839,8 @@ function errorText2(error2) {
|
|
|
5511
5839
|
}
|
|
5512
5840
|
|
|
5513
5841
|
// src/operations/recovery.ts
|
|
5514
|
-
var
|
|
5515
|
-
var
|
|
5842
|
+
var import_node_fs16 = require("node:fs");
|
|
5843
|
+
var import_node_path18 = require("node:path");
|
|
5516
5844
|
var import_node_sqlite3 = require("node:sqlite");
|
|
5517
5845
|
var MAX_AUDIT_EVENTS = 1e3;
|
|
5518
5846
|
var AUDIT_ACTOR = "local-recovery";
|
|
@@ -5527,13 +5855,13 @@ async function recoverAdminPassword(options) {
|
|
|
5527
5855
|
if (typeof options.password !== "string" || options.password.length === 0 || options.password.length > MAX_BROWSER_PASSWORD_CHARS) {
|
|
5528
5856
|
throw new OperationsError("invalid-password", `password must be 1..${MAX_BROWSER_PASSWORD_CHARS} characters`);
|
|
5529
5857
|
}
|
|
5530
|
-
if (!(0,
|
|
5858
|
+
if (!(0, import_node_fs16.existsSync)(database)) {
|
|
5531
5859
|
throw new OperationsError("missing-database", `hub database does not exist: ${database}`);
|
|
5532
5860
|
}
|
|
5533
5861
|
assertPrivateRegularFile(database, "database");
|
|
5534
|
-
const ownLock = (0,
|
|
5862
|
+
const ownLock = (0, import_node_path18.resolve)(`${database}.hub.lock`);
|
|
5535
5863
|
const otherLock = findHubLock(database);
|
|
5536
|
-
if (otherLock !== null && (0,
|
|
5864
|
+
if (otherLock !== null && (0, import_node_path18.resolve)(otherLock) !== ownLock) {
|
|
5537
5865
|
throw new OperationsError(
|
|
5538
5866
|
"hub-active",
|
|
5539
5867
|
`a hub lock exists at ${otherLock}; stop the hub and inspect that lock before recovery`
|
|
@@ -5631,10 +5959,10 @@ async function recoverAdminPassword(options) {
|
|
|
5631
5959
|
}
|
|
5632
5960
|
|
|
5633
5961
|
// src/cli/system.ts
|
|
5634
|
-
var
|
|
5962
|
+
var import_node_fs17 = require("node:fs");
|
|
5635
5963
|
var import_node_child_process5 = require("node:child_process");
|
|
5636
|
-
var
|
|
5637
|
-
var
|
|
5964
|
+
var import_node_crypto12 = require("node:crypto");
|
|
5965
|
+
var import_node_path19 = require("node:path");
|
|
5638
5966
|
var import_node_sqlite4 = require("node:sqlite");
|
|
5639
5967
|
var import_node_util = require("node:util");
|
|
5640
5968
|
var SYSTEM_SCOPE = "system";
|
|
@@ -5744,24 +6072,24 @@ function createSystemHost(overrides = {}) {
|
|
|
5744
6072
|
}
|
|
5745
6073
|
function defaultSystemPaths(overrides = {}) {
|
|
5746
6074
|
return {
|
|
5747
|
-
prefix: (0,
|
|
5748
|
-
configDir: (0,
|
|
5749
|
-
stateDir: (0,
|
|
5750
|
-
unitsDir: (0,
|
|
5751
|
-
sysusersDir: (0,
|
|
5752
|
-
udevRulesDir: (0,
|
|
5753
|
-
powercapRoot: (0,
|
|
6075
|
+
prefix: (0, import_node_path19.resolve)(overrides.prefix ?? "/opt/rigscope"),
|
|
6076
|
+
configDir: (0, import_node_path19.resolve)(overrides.configDir ?? "/etc/rigscope"),
|
|
6077
|
+
stateDir: (0, import_node_path19.resolve)(overrides.stateDir ?? "/var/lib/rigscope"),
|
|
6078
|
+
unitsDir: (0, import_node_path19.resolve)(overrides.unitsDir ?? "/etc/systemd/system"),
|
|
6079
|
+
sysusersDir: (0, import_node_path19.resolve)(overrides.sysusersDir ?? "/etc/sysusers.d"),
|
|
6080
|
+
udevRulesDir: (0, import_node_path19.resolve)(overrides.udevRulesDir ?? "/etc/udev/rules.d"),
|
|
6081
|
+
powercapRoot: (0, import_node_path19.resolve)(overrides.powercapRoot ?? "/sys/class/powercap")
|
|
5754
6082
|
};
|
|
5755
6083
|
}
|
|
5756
6084
|
function unitNamesForComponents(components) {
|
|
5757
6085
|
return COMPONENTS3.filter((component) => componentSet(components)[component]).map(unitFor);
|
|
5758
6086
|
}
|
|
5759
6087
|
function isWithin(parent, candidate) {
|
|
5760
|
-
const rel = (0,
|
|
5761
|
-
return rel === "" || rel !== ".." && !rel.startsWith(`..${
|
|
6088
|
+
const rel = (0, import_node_path19.relative)((0, import_node_path19.resolve)(parent), (0, import_node_path19.resolve)(candidate));
|
|
6089
|
+
return rel === "" || rel !== ".." && !rel.startsWith(`..${import_node_path19.sep}`) && !(0, import_node_path19.isAbsolute)(rel);
|
|
5762
6090
|
}
|
|
5763
6091
|
function ensureAbsolute(path2, label3) {
|
|
5764
|
-
const absolute = (0,
|
|
6092
|
+
const absolute = (0, import_node_path19.resolve)(path2);
|
|
5765
6093
|
if (/[\0\r\n]/.test(absolute)) throw new SystemError("unsafe-path", `${label3} contains control characters`);
|
|
5766
6094
|
if (absolute === "/") throw new SystemError("unsafe-path", `${label3} must not be the filesystem root`);
|
|
5767
6095
|
for (const forbidden of ["/home", "/root", "/proc", "/sys", "/dev", "/boot"]) {
|
|
@@ -5775,7 +6103,7 @@ function validateSystemPaths(input = {}) {
|
|
|
5775
6103
|
const paths = defaultSystemPaths(input);
|
|
5776
6104
|
for (const [label3, value] of Object.entries(paths)) {
|
|
5777
6105
|
if (label3 === "powercapRoot") {
|
|
5778
|
-
if (!(0,
|
|
6106
|
+
if (!(0, import_node_path19.isAbsolute)(value) || /[\0\r\n]/.test(value) || (0, import_node_path19.resolve)(value) === "/") {
|
|
5779
6107
|
throw new SystemError("unsafe-path", `powercap root is unsafe: ${value}`);
|
|
5780
6108
|
}
|
|
5781
6109
|
} else {
|
|
@@ -5831,18 +6159,18 @@ function runMaybe(host, command, args, options) {
|
|
|
5831
6159
|
return host.run(command, args, options);
|
|
5832
6160
|
}
|
|
5833
6161
|
function sha256File2(path2) {
|
|
5834
|
-
return (0,
|
|
6162
|
+
return (0, import_node_crypto12.createHash)("sha256").update((0, import_node_fs17.readFileSync)(path2)).digest("hex");
|
|
5835
6163
|
}
|
|
5836
6164
|
function atomicWrite(path2, content, mode) {
|
|
5837
|
-
(0,
|
|
5838
|
-
const temporary = (0,
|
|
6165
|
+
(0, import_node_fs17.mkdirSync)((0, import_node_path19.dirname)(path2), { recursive: true, mode: 493 });
|
|
6166
|
+
const temporary = (0, import_node_path19.join)((0, import_node_path19.dirname)(path2), `.${(0, import_node_path19.basename)(path2)}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
5839
6167
|
try {
|
|
5840
|
-
(0,
|
|
5841
|
-
(0,
|
|
5842
|
-
(0,
|
|
6168
|
+
(0, import_node_fs17.writeFileSync)(temporary, content, { mode });
|
|
6169
|
+
(0, import_node_fs17.chmodSync)(temporary, mode);
|
|
6170
|
+
(0, import_node_fs17.renameSync)(temporary, path2);
|
|
5843
6171
|
} catch (error2) {
|
|
5844
6172
|
try {
|
|
5845
|
-
(0,
|
|
6173
|
+
(0, import_node_fs17.unlinkSync)(temporary);
|
|
5846
6174
|
} catch {
|
|
5847
6175
|
}
|
|
5848
6176
|
throw error2;
|
|
@@ -5851,12 +6179,12 @@ function atomicWrite(path2, content, mode) {
|
|
|
5851
6179
|
function ensureDirectory(path2, mode, privateDirectory2 = false) {
|
|
5852
6180
|
let stat;
|
|
5853
6181
|
try {
|
|
5854
|
-
stat = (0,
|
|
6182
|
+
stat = (0, import_node_fs17.lstatSync)(path2);
|
|
5855
6183
|
} catch (error2) {
|
|
5856
6184
|
if (error2.code !== "ENOENT") throw error2;
|
|
5857
|
-
(0,
|
|
5858
|
-
(0,
|
|
5859
|
-
stat = (0,
|
|
6185
|
+
(0, import_node_fs17.mkdirSync)(path2, { recursive: true, mode });
|
|
6186
|
+
(0, import_node_fs17.chmodSync)(path2, mode);
|
|
6187
|
+
stat = (0, import_node_fs17.lstatSync)(path2);
|
|
5860
6188
|
}
|
|
5861
6189
|
if (!stat.isDirectory() || stat.isSymbolicLink()) {
|
|
5862
6190
|
throw new SystemError("unsafe-path", `${path2} must be a real directory`);
|
|
@@ -5871,8 +6199,8 @@ function isDefaultSystemLayout(paths) {
|
|
|
5871
6199
|
}
|
|
5872
6200
|
function assertManagedPathSafety(paths, enforceRoot) {
|
|
5873
6201
|
for (const path2 of [paths.prefix, paths.configDir, paths.stateDir, paths.unitsDir, paths.sysusersDir, paths.udevRulesDir]) {
|
|
5874
|
-
if (!(0,
|
|
5875
|
-
const stat = (0,
|
|
6202
|
+
if (!(0, import_node_fs17.existsSync)(path2)) continue;
|
|
6203
|
+
const stat = (0, import_node_fs17.lstatSync)(path2);
|
|
5876
6204
|
if (!stat.isDirectory() || stat.isSymbolicLink()) {
|
|
5877
6205
|
throw new SystemError("unsafe-path", `${path2} must be a real directory`);
|
|
5878
6206
|
}
|
|
@@ -5885,8 +6213,8 @@ function assertManagedPathSafety(paths, enforceRoot) {
|
|
|
5885
6213
|
}
|
|
5886
6214
|
}
|
|
5887
6215
|
function writeManagedFile(path2, content, mode, replace) {
|
|
5888
|
-
if ((0,
|
|
5889
|
-
const stat = (0,
|
|
6216
|
+
if ((0, import_node_fs17.existsSync)(path2)) {
|
|
6217
|
+
const stat = (0, import_node_fs17.lstatSync)(path2);
|
|
5890
6218
|
if (!stat.isFile() || stat.isSymbolicLink()) {
|
|
5891
6219
|
throw new SystemError("unsafe-path", `${path2} must be a regular file, not a symlink`);
|
|
5892
6220
|
}
|
|
@@ -5925,7 +6253,7 @@ function parseEnvValue(value) {
|
|
|
5925
6253
|
function readEnvDocument(path2) {
|
|
5926
6254
|
let raw;
|
|
5927
6255
|
try {
|
|
5928
|
-
raw = (0,
|
|
6256
|
+
raw = (0, import_node_fs17.readFileSync)(path2, "utf8");
|
|
5929
6257
|
} catch (error2) {
|
|
5930
6258
|
if (error2.code === "ENOENT") return null;
|
|
5931
6259
|
throw error2;
|
|
@@ -5972,43 +6300,43 @@ function connectDestinationUrl(value) {
|
|
|
5972
6300
|
return url.href;
|
|
5973
6301
|
}
|
|
5974
6302
|
function hubDatabasePath(paths) {
|
|
5975
|
-
return (0,
|
|
6303
|
+
return (0, import_node_path19.join)(paths.stateDir, "hub", "telemetry.sqlite");
|
|
5976
6304
|
}
|
|
5977
6305
|
function hubEnrollmentPath(paths) {
|
|
5978
|
-
return (0,
|
|
6306
|
+
return (0, import_node_path19.join)(paths.stateDir, "hub", "enrollment.json");
|
|
5979
6307
|
}
|
|
5980
6308
|
function hubSocketPath(paths) {
|
|
5981
|
-
return (0,
|
|
6309
|
+
return (0, import_node_path19.join)(paths.stateDir, "hub", "run", "hub.sock");
|
|
5982
6310
|
}
|
|
5983
6311
|
function collectorStatePath2(paths) {
|
|
5984
|
-
return (0,
|
|
6312
|
+
return (0, import_node_path19.join)(paths.stateDir, "collector", "state.json");
|
|
5985
6313
|
}
|
|
5986
6314
|
function hubEnvPath(paths) {
|
|
5987
|
-
return (0,
|
|
6315
|
+
return (0, import_node_path19.join)(paths.configDir, "hub.env");
|
|
5988
6316
|
}
|
|
5989
6317
|
function collectorEnvPath(paths) {
|
|
5990
|
-
return (0,
|
|
6318
|
+
return (0, import_node_path19.join)(paths.configDir, "collector.env");
|
|
5991
6319
|
}
|
|
5992
6320
|
function sysusersPath(paths) {
|
|
5993
|
-
return (0,
|
|
6321
|
+
return (0, import_node_path19.join)(paths.sysusersDir, SYSUSERS_NAME);
|
|
5994
6322
|
}
|
|
5995
6323
|
function powerSysusersPath(paths) {
|
|
5996
|
-
return (0,
|
|
6324
|
+
return (0, import_node_path19.join)(paths.sysusersDir, POWER_SYSUSERS_NAME);
|
|
5997
6325
|
}
|
|
5998
6326
|
function raplRulePath(paths) {
|
|
5999
|
-
return (0,
|
|
6327
|
+
return (0, import_node_path19.join)(paths.udevRulesDir, RAPL_RULE_NAME);
|
|
6000
6328
|
}
|
|
6001
6329
|
function stateFilePath(paths) {
|
|
6002
|
-
return (0,
|
|
6330
|
+
return (0, import_node_path19.join)(paths.stateDir, STATE_FILE_NAME);
|
|
6003
6331
|
}
|
|
6004
6332
|
function readCollectorIdentity(path2) {
|
|
6005
|
-
if (!(0,
|
|
6006
|
-
const stat = (0,
|
|
6333
|
+
if (!(0, import_node_fs17.existsSync)(path2)) return null;
|
|
6334
|
+
const stat = (0, import_node_fs17.lstatSync)(path2);
|
|
6007
6335
|
if (!stat.isFile() || stat.isSymbolicLink()) throw new SystemError("unsafe-path", `${path2} must be a regular file`);
|
|
6008
6336
|
if ((stat.mode & 63) !== 0) throw new SystemError("insecure-permissions", `${path2} must be private (0600)`);
|
|
6009
6337
|
let raw;
|
|
6010
6338
|
try {
|
|
6011
|
-
raw = JSON.parse((0,
|
|
6339
|
+
raw = JSON.parse((0, import_node_fs17.readFileSync)(path2, "utf8"));
|
|
6012
6340
|
} catch {
|
|
6013
6341
|
throw new SystemError("invalid-file", `${path2} is not valid JSON`);
|
|
6014
6342
|
}
|
|
@@ -6042,7 +6370,7 @@ function readCollectorIdentity(path2) {
|
|
|
6042
6370
|
return { collectorId: record.collectorId, destinations };
|
|
6043
6371
|
}
|
|
6044
6372
|
function writeCollectorIdentity(path2, identity) {
|
|
6045
|
-
ensureDirectory((0,
|
|
6373
|
+
ensureDirectory((0, import_node_path19.dirname)(path2), 448, true);
|
|
6046
6374
|
atomicWrite(path2, `${JSON.stringify(identity)}
|
|
6047
6375
|
`, 384);
|
|
6048
6376
|
}
|
|
@@ -6082,7 +6410,7 @@ function ensureHubOwner(paths) {
|
|
|
6082
6410
|
if (!Array.isArray(parsed)) throw new SystemError("invalid-config", "HUB_BROWSER_USERS must be a JSON array");
|
|
6083
6411
|
if (parsed.length > 0) return void 0;
|
|
6084
6412
|
}
|
|
6085
|
-
const password = (0,
|
|
6413
|
+
const password = (0, import_node_crypto12.randomBytes)(18).toString("base64url");
|
|
6086
6414
|
const users = [{ username: "owner", passwordHash: hashPassword(password), machineIds: "*", admin: true }];
|
|
6087
6415
|
writeEnvValue(hubEnvPath(paths), "HUB_BROWSER_USERS", JSON.stringify(users));
|
|
6088
6416
|
return password;
|
|
@@ -6133,7 +6461,7 @@ function updateHubCollectorRegistry(paths, identity) {
|
|
|
6133
6461
|
}
|
|
6134
6462
|
function registerCollectorInHubDatabase(paths, identity, host) {
|
|
6135
6463
|
const database = hubDatabasePath(paths);
|
|
6136
|
-
if (!(0,
|
|
6464
|
+
if (!(0, import_node_fs17.existsSync)(database)) return { inserted: false };
|
|
6137
6465
|
const db = new import_node_sqlite4.DatabaseSync(database, { timeout: 5e3 });
|
|
6138
6466
|
try {
|
|
6139
6467
|
const table = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='collector_registry'").get();
|
|
@@ -6148,7 +6476,7 @@ function registerCollectorInHubDatabase(paths, identity, host) {
|
|
|
6148
6476
|
}
|
|
6149
6477
|
function findCollectorInHubDatabase(paths, collectorId) {
|
|
6150
6478
|
const database = hubDatabasePath(paths);
|
|
6151
|
-
if (!(0,
|
|
6479
|
+
if (!(0, import_node_fs17.existsSync)(database)) return null;
|
|
6152
6480
|
const db = new import_node_sqlite4.DatabaseSync(database, { readOnly: true, timeout: 5e3 });
|
|
6153
6481
|
try {
|
|
6154
6482
|
const table = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='collector_registry'").get();
|
|
@@ -6161,9 +6489,9 @@ function findCollectorInHubDatabase(paths, collectorId) {
|
|
|
6161
6489
|
}
|
|
6162
6490
|
function createLocalEnrollmentGrant(paths, host) {
|
|
6163
6491
|
const database = hubDatabasePath(paths);
|
|
6164
|
-
if (!(0,
|
|
6165
|
-
const token = (0,
|
|
6166
|
-
const tokenHash = (0,
|
|
6492
|
+
if (!(0, import_node_fs17.existsSync)(database)) throw new SystemError("hub-unavailable", "the hub database does not exist yet");
|
|
6493
|
+
const token = (0, import_node_crypto12.randomBytes)(32).toString("base64url");
|
|
6494
|
+
const tokenHash = (0, import_node_crypto12.createHash)("sha256").update(token).digest("hex");
|
|
6167
6495
|
const expiresAt = host.now() + 10 * 60 * 1e3;
|
|
6168
6496
|
const db = new import_node_sqlite4.DatabaseSync(database, { timeout: 5e3 });
|
|
6169
6497
|
try {
|
|
@@ -6215,7 +6543,7 @@ async function pairCollectorWithHub(options) {
|
|
|
6215
6543
|
note: "the local hub has no reachable loopback or HTTPS destination"
|
|
6216
6544
|
};
|
|
6217
6545
|
}
|
|
6218
|
-
if (!(0,
|
|
6546
|
+
if (!(0, import_node_fs17.existsSync)((0, import_node_path19.join)(paths.unitsDir, UNIT_NAMES.hub))) {
|
|
6219
6547
|
return { paired: false, awaiting: true, hubWasActive: false, note: "the local hub unit is not installed" };
|
|
6220
6548
|
}
|
|
6221
6549
|
const hubWasActive = systemdActive(host, UNIT_NAMES.hub);
|
|
@@ -6228,7 +6556,7 @@ async function pairCollectorWithHub(options) {
|
|
|
6228
6556
|
destinations: [{ url: destination.url, token: registered.token, sharing: { ...SYSTEM_DEFAULT_SHARING } }]
|
|
6229
6557
|
};
|
|
6230
6558
|
writeCollectorIdentity(collectorStatePath2(paths), adopted);
|
|
6231
|
-
chownAccount([(0,
|
|
6559
|
+
chownAccount([(0, import_node_path19.join)(paths.stateDir, "collector")], accounts.collector, accounts.collector, host);
|
|
6232
6560
|
return { paired: true, awaiting: false, hubWasActive, destination: destination.url };
|
|
6233
6561
|
}
|
|
6234
6562
|
}
|
|
@@ -6236,7 +6564,7 @@ async function pairCollectorWithHub(options) {
|
|
|
6236
6564
|
try {
|
|
6237
6565
|
grant = createLocalEnrollmentGrant(paths, host);
|
|
6238
6566
|
} catch (error2) {
|
|
6239
|
-
chownAccount([(0,
|
|
6567
|
+
chownAccount([(0, import_node_path19.join)(paths.stateDir, "collector")], accounts.collector, accounts.collector, host);
|
|
6240
6568
|
return {
|
|
6241
6569
|
paired: false,
|
|
6242
6570
|
awaiting: true,
|
|
@@ -6254,18 +6582,18 @@ async function pairCollectorWithHub(options) {
|
|
|
6254
6582
|
note: `enrollment through the live hub failed: ${error2 instanceof Error ? error2.message : String(error2)}`
|
|
6255
6583
|
};
|
|
6256
6584
|
} finally {
|
|
6257
|
-
chownAccount([(0,
|
|
6585
|
+
chownAccount([(0, import_node_path19.join)(paths.stateDir, "collector")], accounts.collector, accounts.collector, host);
|
|
6258
6586
|
}
|
|
6259
6587
|
if (!collectorConfigured(paths).configured) {
|
|
6260
6588
|
return { paired: false, awaiting: true, hubWasActive, note: "the hub accepted enrollment but no destination was saved" };
|
|
6261
6589
|
}
|
|
6262
|
-
chownAccount([(0,
|
|
6590
|
+
chownAccount([(0, import_node_path19.join)(paths.stateDir, "collector")], accounts.collector, accounts.collector, host);
|
|
6263
6591
|
return { paired: true, awaiting: false, hubWasActive, destination: destination.url };
|
|
6264
6592
|
}
|
|
6265
6593
|
const identity = {
|
|
6266
|
-
collectorId: existing?.collectorId ?? (0,
|
|
6267
|
-
machineId: (0,
|
|
6268
|
-
token: (0,
|
|
6594
|
+
collectorId: existing?.collectorId ?? (0, import_node_crypto12.randomUUID)(),
|
|
6595
|
+
machineId: (0, import_node_crypto12.randomUUID)(),
|
|
6596
|
+
token: (0, import_node_crypto12.randomBytes)(32).toString("base64url")
|
|
6269
6597
|
};
|
|
6270
6598
|
const registry = registerCollectorInHubDatabase(paths, identity, host);
|
|
6271
6599
|
let token = identity.token;
|
|
@@ -6292,7 +6620,7 @@ async function pairCollectorWithHub(options) {
|
|
|
6292
6620
|
}
|
|
6293
6621
|
];
|
|
6294
6622
|
writeCollectorIdentity(collectorStatePath2(paths), next);
|
|
6295
|
-
chownAccount([(0,
|
|
6623
|
+
chownAccount([(0, import_node_path19.join)(paths.stateDir, "collector")], accounts.collector, accounts.collector, host);
|
|
6296
6624
|
return { paired: true, awaiting: false, hubWasActive, destination: destination.url };
|
|
6297
6625
|
}
|
|
6298
6626
|
function unitCommon(name, description, paths, account, envPath, execStart, extraService = []) {
|
|
@@ -6309,7 +6637,7 @@ function unitCommon(name, description, paths, account, envPath, execStart, extra
|
|
|
6309
6637
|
"Type=simple",
|
|
6310
6638
|
`User=${account}`,
|
|
6311
6639
|
`Group=${account}`,
|
|
6312
|
-
`WorkingDirectory=${(0,
|
|
6640
|
+
`WorkingDirectory=${(0, import_node_path19.join)(paths.prefix, "current").replace(/%/g, "%%")}`,
|
|
6313
6641
|
`EnvironmentFile=${envPath.replace(/%/g, "%%")}`,
|
|
6314
6642
|
"Environment=NODE_ENV=production",
|
|
6315
6643
|
"Restart=on-failure",
|
|
@@ -6344,13 +6672,13 @@ function unitCommon(name, description, paths, account, envPath, execStart, extra
|
|
|
6344
6672
|
}
|
|
6345
6673
|
function renderSystemHubUnit(options) {
|
|
6346
6674
|
const { paths, accounts } = options;
|
|
6347
|
-
const hubScript = (0,
|
|
6675
|
+
const hubScript = (0, import_node_path19.join)(paths.prefix, "current", "dist", "hub.cjs");
|
|
6348
6676
|
const extra = [
|
|
6349
6677
|
`Environment=${systemdQuote(`HUB_DATABASE_PATH=${options.database}`)}`,
|
|
6350
6678
|
`Environment=${systemdQuote(`HUB_STATE_FILE=${options.enrollment}`)}`,
|
|
6351
6679
|
...options.remote ? [`Environment=${systemdQuote(`HUB_SOCKET_PATH=${options.socket}`)}`] : [],
|
|
6352
|
-
`ReadWritePaths=${systemdQuote((0,
|
|
6353
|
-
`ReadOnlyPaths=${systemdQuote((0,
|
|
6680
|
+
`ReadWritePaths=${systemdQuote((0, import_node_path19.join)(paths.stateDir, "hub"))}`,
|
|
6681
|
+
`ReadOnlyPaths=${systemdQuote((0, import_node_path19.join)(paths.prefix, "current"))}`,
|
|
6354
6682
|
"PrivateDevices=yes",
|
|
6355
6683
|
"TimeoutStopSec=15s"
|
|
6356
6684
|
];
|
|
@@ -6369,14 +6697,14 @@ function renderSystemHubUnit(options) {
|
|
|
6369
6697
|
}
|
|
6370
6698
|
function renderSystemCollectorUnit(options) {
|
|
6371
6699
|
const { paths, accounts } = options;
|
|
6372
|
-
const collectorScript = (0,
|
|
6700
|
+
const collectorScript = (0, import_node_path19.join)(paths.prefix, "current", "dist", "collector.cjs");
|
|
6373
6701
|
const extra = [
|
|
6374
6702
|
...options.powerAccess ? [`SupplementaryGroups=${accounts.powerGroup}`] : [],
|
|
6375
6703
|
`Environment=${systemdQuote(`COLLECTOR_MODE=real`)}`,
|
|
6376
6704
|
`Environment=${systemdQuote(`COLLECTOR_STATE_FILE=${options.collectorState}`)}`,
|
|
6377
|
-
`Environment=${systemdQuote(`COLLECTOR_HEALTH_FILE=${(0,
|
|
6378
|
-
`ReadWritePaths=${systemdQuote((0,
|
|
6379
|
-
`ReadOnlyPaths=${systemdQuote((0,
|
|
6705
|
+
`Environment=${systemdQuote(`COLLECTOR_HEALTH_FILE=${(0, import_node_path19.join)(paths.stateDir, "collector", "health.json")}`)}`,
|
|
6706
|
+
`ReadWritePaths=${systemdQuote((0, import_node_path19.join)(paths.stateDir, "collector"))}`,
|
|
6707
|
+
`ReadOnlyPaths=${systemdQuote((0, import_node_path19.join)(paths.prefix, "current"))}`,
|
|
6380
6708
|
"TimeoutStopSec=10s"
|
|
6381
6709
|
];
|
|
6382
6710
|
return [
|
|
@@ -6449,11 +6777,15 @@ function collectorEnvTemplate() {
|
|
|
6449
6777
|
"# COLLECTOR_ENROLL_URL=ws://127.0.0.1:8081/api/collector/connect",
|
|
6450
6778
|
"# COLLECTOR_ENROLL_TOKEN=<one-use grant>",
|
|
6451
6779
|
"# COLLECTOR_MODE=real",
|
|
6780
|
+
"# Unacknowledged samples wait in RAM by default: no queue is written to disk",
|
|
6781
|
+
"# and a collector restart loses what was never acknowledged. Set this to durable",
|
|
6782
|
+
"# to keep them in a per-hub SQLite outbox across collector restarts.",
|
|
6783
|
+
"# COLLECTOR_QUEUE_MODE=durable",
|
|
6452
6784
|
""
|
|
6453
6785
|
].join("\n");
|
|
6454
6786
|
}
|
|
6455
6787
|
function assertPrivateSourceFile(path2, label3) {
|
|
6456
|
-
const stat = (0,
|
|
6788
|
+
const stat = (0, import_node_fs17.lstatSync)(path2);
|
|
6457
6789
|
if (!stat.isFile() || stat.isSymbolicLink()) {
|
|
6458
6790
|
throw new SystemError("unsafe-adoption", `${label3} must be a regular file: ${path2}`);
|
|
6459
6791
|
}
|
|
@@ -6464,7 +6796,7 @@ function assertPrivateSourceFile(path2, label3) {
|
|
|
6464
6796
|
function readJsonObject(path2) {
|
|
6465
6797
|
let raw;
|
|
6466
6798
|
try {
|
|
6467
|
-
raw = (0,
|
|
6799
|
+
raw = (0, import_node_fs17.readFileSync)(path2, "utf8");
|
|
6468
6800
|
} catch (error2) {
|
|
6469
6801
|
throw new SystemError("missing-file", `cannot read ${path2}: ${error2.message}`);
|
|
6470
6802
|
}
|
|
@@ -6487,8 +6819,8 @@ function isCanonicalComponents(value) {
|
|
|
6487
6819
|
}
|
|
6488
6820
|
function readSystemState(paths) {
|
|
6489
6821
|
const path2 = stateFilePath(paths);
|
|
6490
|
-
if (!(0,
|
|
6491
|
-
const stat = (0,
|
|
6822
|
+
if (!(0, import_node_fs17.existsSync)(path2)) return null;
|
|
6823
|
+
const stat = (0, import_node_fs17.lstatSync)(path2);
|
|
6492
6824
|
if (!stat.isFile() || stat.isSymbolicLink()) throw new SystemError("unsafe-path", `${path2} must be a regular file`);
|
|
6493
6825
|
if ((stat.mode & 63) !== 0) throw new SystemError("insecure-permissions", `${path2} must be 0600`);
|
|
6494
6826
|
const raw = readJsonObject(path2);
|
|
@@ -6520,7 +6852,7 @@ function readSystemState(paths) {
|
|
|
6520
6852
|
}
|
|
6521
6853
|
function systemStateIsLegacy(paths) {
|
|
6522
6854
|
const path2 = stateFilePath(paths);
|
|
6523
|
-
if (!(0,
|
|
6855
|
+
if (!(0, import_node_fs17.existsSync)(path2)) return false;
|
|
6524
6856
|
let raw;
|
|
6525
6857
|
try {
|
|
6526
6858
|
raw = readJsonObject(path2);
|
|
@@ -6571,24 +6903,24 @@ function validateVersion2(value) {
|
|
|
6571
6903
|
return value;
|
|
6572
6904
|
}
|
|
6573
6905
|
function releaseVersion(root) {
|
|
6574
|
-
const metadata = readJsonObject((0,
|
|
6906
|
+
const metadata = readJsonObject((0, import_node_path19.join)(root, "package.json"));
|
|
6575
6907
|
if (Object.hasOwn(metadata, "rigscopeConfigVersion")) {
|
|
6576
6908
|
throw new SystemError("invalid-release", "release uses unfinished configuration metadata; select a canonical release");
|
|
6577
6909
|
}
|
|
6578
6910
|
return validateVersion2(metadata.version);
|
|
6579
6911
|
}
|
|
6580
6912
|
function releaseSchemaVersion(root) {
|
|
6581
|
-
const manifestPath = (0,
|
|
6582
|
-
if (!(0,
|
|
6913
|
+
const manifestPath = (0, import_node_path19.join)(root, "manifest.json");
|
|
6914
|
+
if (!(0, import_node_fs17.existsSync)(manifestPath)) return null;
|
|
6583
6915
|
const manifest = readJsonObject(manifestPath);
|
|
6584
6916
|
return Number.isSafeInteger(manifest.schemaVersion) ? Number(manifest.schemaVersion) : null;
|
|
6585
6917
|
}
|
|
6586
6918
|
function assertReleaseArtifacts(root) {
|
|
6587
6919
|
for (const artifact of REQUIRED_ARTIFACTS) {
|
|
6588
|
-
const path2 = (0,
|
|
6920
|
+
const path2 = (0, import_node_path19.join)(root, artifact);
|
|
6589
6921
|
let stat;
|
|
6590
6922
|
try {
|
|
6591
|
-
stat = (0,
|
|
6923
|
+
stat = (0, import_node_fs17.lstatSync)(path2);
|
|
6592
6924
|
} catch {
|
|
6593
6925
|
throw new SystemError("missing-artifact", `release is missing ${artifact}`);
|
|
6594
6926
|
}
|
|
@@ -6596,12 +6928,12 @@ function assertReleaseArtifacts(root) {
|
|
|
6596
6928
|
throw new SystemError("invalid-artifact", `release artifact is not a non-empty regular file: ${artifact}`);
|
|
6597
6929
|
}
|
|
6598
6930
|
}
|
|
6599
|
-
const buildId = (0,
|
|
6931
|
+
const buildId = (0, import_node_fs17.readFileSync)((0, import_node_path19.join)(root, ".next", "BUILD_ID"), "utf8").trim();
|
|
6600
6932
|
if (buildId === "" || /\s/.test(buildId)) throw new SystemError("invalid-artifact", ".next/BUILD_ID is invalid");
|
|
6601
6933
|
for (const directory of [".next/server", ".next/static"]) {
|
|
6602
6934
|
let stat;
|
|
6603
6935
|
try {
|
|
6604
|
-
stat = (0,
|
|
6936
|
+
stat = (0, import_node_fs17.lstatSync)((0, import_node_path19.join)(root, directory));
|
|
6605
6937
|
} catch {
|
|
6606
6938
|
throw new SystemError("missing-artifact", `release is missing ${directory}/`);
|
|
6607
6939
|
}
|
|
@@ -6609,10 +6941,10 @@ function assertReleaseArtifacts(root) {
|
|
|
6609
6941
|
}
|
|
6610
6942
|
}
|
|
6611
6943
|
function verifyReleaseManifest(root) {
|
|
6612
|
-
const manifestPath = (0,
|
|
6613
|
-
if (!(0,
|
|
6944
|
+
const manifestPath = (0, import_node_path19.join)(root, "manifest.json");
|
|
6945
|
+
if (!(0, import_node_fs17.existsSync)(manifestPath)) return;
|
|
6614
6946
|
const manifest = readJsonObject(manifestPath);
|
|
6615
|
-
const packageJson = readJsonObject((0,
|
|
6947
|
+
const packageJson = readJsonObject((0, import_node_path19.join)(root, "package.json"));
|
|
6616
6948
|
if (manifest.name !== void 0 && manifest.name !== packageJson.name) {
|
|
6617
6949
|
throw new SystemError("manifest-mismatch", "release manifest name does not match package.json");
|
|
6618
6950
|
}
|
|
@@ -6631,17 +6963,17 @@ function verifyReleaseManifest(root) {
|
|
|
6631
6963
|
if (typeof relativePath !== "string" || relativePath === "" || relativePath.startsWith("/") || relativePath.includes("\\") || relativePath.split("/").includes("..")) {
|
|
6632
6964
|
throw new SystemError("invalid-manifest", `release manifest contains an unsafe path: ${String(relativePath)}`);
|
|
6633
6965
|
}
|
|
6634
|
-
const absolute = (0,
|
|
6635
|
-
const stat = (0,
|
|
6966
|
+
const absolute = (0, import_node_path19.join)(root, relativePath);
|
|
6967
|
+
const stat = (0, import_node_fs17.lstatSync)(absolute);
|
|
6636
6968
|
if (!stat.isFile() || stat.isSymbolicLink()) throw new SystemError("invalid-manifest", `release artifact is not a regular file: ${relativePath}`);
|
|
6637
6969
|
if (entry2.bytes !== stat.size) throw new SystemError("artifact-mismatch", `release artifact size changed: ${relativePath}`);
|
|
6638
6970
|
if (entry2.sha256 !== sha256File2(absolute)) throw new SystemError("artifact-mismatch", `release artifact hash changed: ${relativePath}`);
|
|
6639
6971
|
listed.add(relativePath);
|
|
6640
6972
|
}
|
|
6641
6973
|
const visit = (current) => {
|
|
6642
|
-
for (const entry2 of (0,
|
|
6643
|
-
const absolute = (0,
|
|
6644
|
-
const rel = (0,
|
|
6974
|
+
for (const entry2 of (0, import_node_fs17.readdirSync)(current, { withFileTypes: true })) {
|
|
6975
|
+
const absolute = (0, import_node_path19.join)(current, entry2.name);
|
|
6976
|
+
const rel = (0, import_node_path19.relative)(root, absolute).split(import_node_path19.sep).join("/");
|
|
6645
6977
|
if (rel === "node_modules" || rel.startsWith("node_modules/") || rel === ".next/cache" || rel.startsWith(".next/cache/")) continue;
|
|
6646
6978
|
if (entry2.isSymbolicLink()) throw new SystemError("unsafe-release", `release contains a symlink: ${rel}`);
|
|
6647
6979
|
if (entry2.isDirectory()) {
|
|
@@ -6656,49 +6988,49 @@ function verifyReleaseManifest(root) {
|
|
|
6656
6988
|
}
|
|
6657
6989
|
function assertNoSymlinks(root) {
|
|
6658
6990
|
const visit = (path2) => {
|
|
6659
|
-
const stat = (0,
|
|
6660
|
-
if (stat.isSymbolicLink()) throw new SystemError("unsafe-release", `release contains a symlink: ${(0,
|
|
6991
|
+
const stat = (0, import_node_fs17.lstatSync)(path2);
|
|
6992
|
+
if (stat.isSymbolicLink()) throw new SystemError("unsafe-release", `release contains a symlink: ${(0, import_node_path19.relative)(root, path2)}`);
|
|
6661
6993
|
if (!stat.isDirectory()) return;
|
|
6662
|
-
for (const entry2 of (0,
|
|
6994
|
+
for (const entry2 of (0, import_node_fs17.readdirSync)(path2)) visit((0, import_node_path19.join)(path2, entry2));
|
|
6663
6995
|
};
|
|
6664
6996
|
visit(root);
|
|
6665
6997
|
}
|
|
6666
6998
|
function copyReleaseTree(source, destination) {
|
|
6667
6999
|
const visit = (current, target) => {
|
|
6668
|
-
const stat = (0,
|
|
6669
|
-
if (stat.isSymbolicLink()) throw new SystemError("unsafe-release", `source contains a symlink: ${(0,
|
|
7000
|
+
const stat = (0, import_node_fs17.lstatSync)(current);
|
|
7001
|
+
if (stat.isSymbolicLink()) throw new SystemError("unsafe-release", `source contains a symlink: ${(0, import_node_path19.relative)(source, current)}`);
|
|
6670
7002
|
if (stat.isDirectory()) {
|
|
6671
|
-
(0,
|
|
6672
|
-
for (const entry2 of (0,
|
|
6673
|
-
const child = (0,
|
|
6674
|
-
const rel = (0,
|
|
7003
|
+
(0, import_node_fs17.mkdirSync)(target, { recursive: true, mode: 493 });
|
|
7004
|
+
for (const entry2 of (0, import_node_fs17.readdirSync)(current)) {
|
|
7005
|
+
const child = (0, import_node_path19.join)(current, entry2);
|
|
7006
|
+
const rel = (0, import_node_path19.relative)(source, child);
|
|
6675
7007
|
if (rel === ".git" || rel === ".next-dev" || rel === ".next/cache" || rel === "node_modules" || rel.startsWith("node_modules/")) {
|
|
6676
7008
|
continue;
|
|
6677
7009
|
}
|
|
6678
|
-
visit(child, (0,
|
|
7010
|
+
visit(child, (0, import_node_path19.join)(target, entry2));
|
|
6679
7011
|
}
|
|
6680
7012
|
return;
|
|
6681
7013
|
}
|
|
6682
|
-
if (!stat.isFile()) throw new SystemError("unsafe-release", `source contains a non-regular file: ${(0,
|
|
6683
|
-
(0,
|
|
6684
|
-
(0,
|
|
6685
|
-
(0,
|
|
7014
|
+
if (!stat.isFile()) throw new SystemError("unsafe-release", `source contains a non-regular file: ${(0, import_node_path19.relative)(source, current)}`);
|
|
7015
|
+
(0, import_node_fs17.mkdirSync)((0, import_node_path19.dirname)(target), { recursive: true, mode: 493 });
|
|
7016
|
+
(0, import_node_fs17.copyFileSync)(current, target);
|
|
7017
|
+
(0, import_node_fs17.chmodSync)(target, 420);
|
|
6686
7018
|
};
|
|
6687
7019
|
visit(source, destination);
|
|
6688
7020
|
}
|
|
6689
7021
|
function copyReleaseAllowlisted(source, destination) {
|
|
6690
|
-
for (const entry2 of (0,
|
|
7022
|
+
for (const entry2 of (0, import_node_fs17.readdirSync)(source)) {
|
|
6691
7023
|
if (!PACKAGE_TOP_LEVEL.has(entry2)) continue;
|
|
6692
7024
|
if (entry2 === "node_modules") continue;
|
|
6693
|
-
const child = (0,
|
|
6694
|
-
const target = (0,
|
|
6695
|
-
const stat = (0,
|
|
7025
|
+
const child = (0, import_node_path19.join)(source, entry2);
|
|
7026
|
+
const target = (0, import_node_path19.join)(destination, entry2);
|
|
7027
|
+
const stat = (0, import_node_fs17.lstatSync)(child);
|
|
6696
7028
|
if (stat.isSymbolicLink()) throw new SystemError("unsafe-release", `source contains a symlink: ${entry2}`);
|
|
6697
7029
|
if (stat.isDirectory()) {
|
|
6698
7030
|
copyReleaseTree(child, target);
|
|
6699
7031
|
} else if (stat.isFile()) {
|
|
6700
|
-
(0,
|
|
6701
|
-
(0,
|
|
7032
|
+
(0, import_node_fs17.copyFileSync)(child, target);
|
|
7033
|
+
(0, import_node_fs17.chmodSync)(target, 420);
|
|
6702
7034
|
}
|
|
6703
7035
|
}
|
|
6704
7036
|
}
|
|
@@ -6733,28 +7065,28 @@ function extractArchive(archive, stage, host) {
|
|
|
6733
7065
|
}
|
|
6734
7066
|
function discardStagedRelease(staged) {
|
|
6735
7067
|
if (staged === null) return;
|
|
6736
|
-
(0,
|
|
7068
|
+
(0, import_node_fs17.rmSync)(staged.stageDir, { recursive: true, force: true });
|
|
6737
7069
|
}
|
|
6738
7070
|
function releaseTargetDir(paths, version) {
|
|
6739
|
-
return (0,
|
|
7071
|
+
return (0, import_node_path19.join)(paths.prefix, "releases", version);
|
|
6740
7072
|
}
|
|
6741
7073
|
function assertReleaseTargetAvailable(paths, releaseDir, replaceRelease) {
|
|
6742
|
-
if (!(0,
|
|
7074
|
+
if (!(0, import_node_fs17.existsSync)(releaseDir)) return;
|
|
6743
7075
|
const current = currentReleaseDir(paths);
|
|
6744
7076
|
const previous = previousReleaseDir(paths);
|
|
6745
7077
|
if (!replaceRelease || current === releaseDir || previous === releaseDir) {
|
|
6746
7078
|
throw new SystemError(
|
|
6747
7079
|
"release-exists",
|
|
6748
|
-
`release ${(0,
|
|
7080
|
+
`release ${(0, import_node_path19.basename)(releaseDir)} is already installed${current === releaseDir || previous === releaseDir ? " or retained" : ""}; choose a new version`
|
|
6749
7081
|
);
|
|
6750
7082
|
}
|
|
6751
7083
|
}
|
|
6752
7084
|
function stageRelease(options) {
|
|
6753
|
-
const source = (0,
|
|
6754
|
-
const stat = (0,
|
|
7085
|
+
const source = (0, import_node_fs17.realpathSync)((0, import_node_path19.resolve)(options.source));
|
|
7086
|
+
const stat = (0, import_node_fs17.lstatSync)(source);
|
|
6755
7087
|
ensureDirectory(options.paths.prefix, 493);
|
|
6756
|
-
const stageDir = (0,
|
|
6757
|
-
(0,
|
|
7088
|
+
const stageDir = (0, import_node_path19.join)(options.paths.prefix, `.stage-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
7089
|
+
(0, import_node_fs17.mkdirSync)(stageDir, { recursive: true, mode: 448 });
|
|
6758
7090
|
try {
|
|
6759
7091
|
if (stat.isDirectory() && !stat.isSymbolicLink()) {
|
|
6760
7092
|
copyReleaseAllowlisted(source, stageDir);
|
|
@@ -6772,7 +7104,7 @@ function stageRelease(options) {
|
|
|
6772
7104
|
artifacts: [...REQUIRED_ARTIFACTS]
|
|
6773
7105
|
};
|
|
6774
7106
|
} catch (error2) {
|
|
6775
|
-
(0,
|
|
7107
|
+
(0, import_node_fs17.rmSync)(stageDir, { recursive: true, force: true });
|
|
6776
7108
|
throw error2;
|
|
6777
7109
|
}
|
|
6778
7110
|
}
|
|
@@ -6798,13 +7130,13 @@ function prepareStagedRelease(options) {
|
|
|
6798
7130
|
}
|
|
6799
7131
|
}
|
|
6800
7132
|
function commitStagedRelease(options) {
|
|
6801
|
-
const releasesDir = (0,
|
|
7133
|
+
const releasesDir = (0, import_node_path19.join)(options.paths.prefix, "releases");
|
|
6802
7134
|
ensureDirectory(releasesDir, 493);
|
|
6803
7135
|
const releaseDir = releaseTargetDir(options.paths, options.staged.version);
|
|
6804
7136
|
assertReleaseTargetAvailable(options.paths, releaseDir, options.replaceRelease);
|
|
6805
|
-
if ((0,
|
|
6806
|
-
(0,
|
|
6807
|
-
ensureDirectory((0,
|
|
7137
|
+
if ((0, import_node_fs17.existsSync)(releaseDir)) (0, import_node_fs17.rmSync)(releaseDir, { recursive: true, force: true });
|
|
7138
|
+
(0, import_node_fs17.renameSync)(options.staged.stageDir, releaseDir);
|
|
7139
|
+
ensureDirectory((0, import_node_path19.join)(releaseDir, ".next", "cache"), 493);
|
|
6808
7140
|
return {
|
|
6809
7141
|
version: options.staged.version,
|
|
6810
7142
|
releaseDir,
|
|
@@ -6813,20 +7145,20 @@ function commitStagedRelease(options) {
|
|
|
6813
7145
|
};
|
|
6814
7146
|
}
|
|
6815
7147
|
function dependencyNames(root) {
|
|
6816
|
-
const pkg = readJsonObject((0,
|
|
7148
|
+
const pkg = readJsonObject((0, import_node_path19.join)(root, "package.json"));
|
|
6817
7149
|
const dependencies2 = pkg.dependencies;
|
|
6818
7150
|
if (dependencies2 === null || typeof dependencies2 !== "object" || Array.isArray(dependencies2)) return [];
|
|
6819
7151
|
return Object.keys(dependencies2).filter((name) => /^[A-Za-z0-9@/._-]+$/.test(name));
|
|
6820
7152
|
}
|
|
6821
7153
|
function missingDependencies(root) {
|
|
6822
|
-
return dependencyNames(root).filter((name) => !(0,
|
|
7154
|
+
return dependencyNames(root).filter((name) => !(0, import_node_fs17.existsSync)((0, import_node_path19.join)(root, "node_modules", name, "package.json")));
|
|
6823
7155
|
}
|
|
6824
7156
|
function installDependencies(root, host, command = "npm") {
|
|
6825
|
-
const hasLock = (0,
|
|
7157
|
+
const hasLock = (0, import_node_fs17.existsSync)((0, import_node_path19.join)(root, "package-lock.json"));
|
|
6826
7158
|
const args = hasLock ? ["ci", "--omit=dev", "--ignore-scripts", "--no-audit", "--no-fund"] : ["install", "--omit=dev", "--ignore-scripts", "--no-audit", "--no-fund"];
|
|
6827
|
-
const siblingNpm = (0,
|
|
6828
|
-
const executable = command === "npm" && (0,
|
|
6829
|
-
const nodeBin = (0,
|
|
7159
|
+
const siblingNpm = (0, import_node_path19.join)((0, import_node_path19.dirname)(process.execPath), "npm");
|
|
7160
|
+
const executable = command === "npm" && (0, import_node_fs17.existsSync)(siblingNpm) ? siblingNpm : command;
|
|
7161
|
+
const nodeBin = (0, import_node_path19.dirname)(process.execPath);
|
|
6830
7162
|
const path2 = [nodeBin, process.env.PATH ?? ""].filter(Boolean).join(":");
|
|
6831
7163
|
runRequired(host, executable, args, "production dependency installation", {
|
|
6832
7164
|
cwd: root,
|
|
@@ -6835,21 +7167,21 @@ function installDependencies(root, host, command = "npm") {
|
|
|
6835
7167
|
});
|
|
6836
7168
|
}
|
|
6837
7169
|
function currentReleaseDir(paths) {
|
|
6838
|
-
const link = (0,
|
|
7170
|
+
const link = (0, import_node_path19.join)(paths.prefix, "current");
|
|
6839
7171
|
try {
|
|
6840
|
-
const target = (0,
|
|
6841
|
-
const absolute = (0,
|
|
6842
|
-
return isWithin((0,
|
|
7172
|
+
const target = (0, import_node_fs17.readlinkSync)(link);
|
|
7173
|
+
const absolute = (0, import_node_path19.isAbsolute)(target) ? target : (0, import_node_path19.resolve)(paths.prefix, target);
|
|
7174
|
+
return isWithin((0, import_node_path19.join)(paths.prefix, "releases"), absolute) ? absolute : null;
|
|
6843
7175
|
} catch {
|
|
6844
7176
|
return null;
|
|
6845
7177
|
}
|
|
6846
7178
|
}
|
|
6847
7179
|
function previousReleaseDir(paths) {
|
|
6848
|
-
const link = (0,
|
|
7180
|
+
const link = (0, import_node_path19.join)(paths.prefix, "previous");
|
|
6849
7181
|
try {
|
|
6850
|
-
const target = (0,
|
|
6851
|
-
const absolute = (0,
|
|
6852
|
-
return isWithin((0,
|
|
7182
|
+
const target = (0, import_node_fs17.readlinkSync)(link);
|
|
7183
|
+
const absolute = (0, import_node_path19.isAbsolute)(target) ? target : (0, import_node_path19.resolve)(paths.prefix, target);
|
|
7184
|
+
return isWithin((0, import_node_path19.join)(paths.prefix, "releases"), absolute) ? absolute : null;
|
|
6853
7185
|
} catch {
|
|
6854
7186
|
return null;
|
|
6855
7187
|
}
|
|
@@ -6857,11 +7189,11 @@ function previousReleaseDir(paths) {
|
|
|
6857
7189
|
function replaceSymlink(link, target, host) {
|
|
6858
7190
|
const temporary = `${link}.tmp-${process.pid}-${Date.now()}`;
|
|
6859
7191
|
try {
|
|
6860
|
-
(0,
|
|
6861
|
-
(0,
|
|
7192
|
+
(0, import_node_fs17.symlinkSync)(target, temporary);
|
|
7193
|
+
(0, import_node_fs17.renameSync)(temporary, link);
|
|
6862
7194
|
} catch (error2) {
|
|
6863
7195
|
try {
|
|
6864
|
-
(0,
|
|
7196
|
+
(0, import_node_fs17.unlinkSync)(temporary);
|
|
6865
7197
|
} catch {
|
|
6866
7198
|
}
|
|
6867
7199
|
throw error2;
|
|
@@ -6870,8 +7202,8 @@ function replaceSymlink(link, target, host) {
|
|
|
6870
7202
|
}
|
|
6871
7203
|
function removeSymlink(link) {
|
|
6872
7204
|
try {
|
|
6873
|
-
const stat = (0,
|
|
6874
|
-
if (stat.isSymbolicLink()) (0,
|
|
7205
|
+
const stat = (0, import_node_fs17.lstatSync)(link);
|
|
7206
|
+
if (stat.isSymbolicLink()) (0, import_node_fs17.unlinkSync)(link);
|
|
6875
7207
|
} catch {
|
|
6876
7208
|
}
|
|
6877
7209
|
}
|
|
@@ -6884,18 +7216,18 @@ function nodeVersion(host, nodePath) {
|
|
|
6884
7216
|
return output;
|
|
6885
7217
|
}
|
|
6886
7218
|
function ensureRootOwnedNode(options) {
|
|
6887
|
-
const selected = (0,
|
|
6888
|
-
const real = (0,
|
|
7219
|
+
const selected = (0, import_node_path19.resolve)(options.nodePath ?? process.execPath);
|
|
7220
|
+
const real = (0, import_node_fs17.realpathSync)(selected);
|
|
6889
7221
|
nodeVersion(options.host, real);
|
|
6890
|
-
const stat = (0,
|
|
6891
|
-
const insideRelease = isWithin((0,
|
|
7222
|
+
const stat = (0, import_node_fs17.statSync)(real);
|
|
7223
|
+
const insideRelease = isWithin((0, import_node_path19.join)(options.paths.prefix, "releases"), real);
|
|
6892
7224
|
const unsafe = stat.uid !== 0 || (stat.mode & 18) !== 0 || options.copyNode === true || insideRelease;
|
|
6893
7225
|
if (!unsafe || options.trustedNode === true) return real;
|
|
6894
|
-
const target = (0,
|
|
7226
|
+
const target = (0, import_node_path19.join)(options.paths.prefix, "node", "node");
|
|
6895
7227
|
if (!options.apply) return target;
|
|
6896
|
-
ensureDirectory((0,
|
|
6897
|
-
(0,
|
|
6898
|
-
(0,
|
|
7228
|
+
ensureDirectory((0, import_node_path19.join)(options.paths.prefix, "node"), 493);
|
|
7229
|
+
(0, import_node_fs17.copyFileSync)(real, target);
|
|
7230
|
+
(0, import_node_fs17.chmodSync)(target, 493);
|
|
6899
7231
|
runRequired(options.host, "chown", ["root:root", target], "node ownership");
|
|
6900
7232
|
nodeVersion(options.host, target);
|
|
6901
7233
|
return target;
|
|
@@ -6924,8 +7256,8 @@ function validatedOrigin(value) {
|
|
|
6924
7256
|
return value;
|
|
6925
7257
|
}
|
|
6926
7258
|
function readAdoptionSetup(source) {
|
|
6927
|
-
const configPath = (0,
|
|
6928
|
-
if (!(0,
|
|
7259
|
+
const configPath = (0, import_node_path19.join)(source, "config.json");
|
|
7260
|
+
if (!(0, import_node_fs17.existsSync)(configPath)) {
|
|
6929
7261
|
throw new SystemError("invalid-adoption", "adopted installation has no config.json");
|
|
6930
7262
|
}
|
|
6931
7263
|
assertPrivateSourceFile(configPath, "adopted setup");
|
|
@@ -6973,35 +7305,35 @@ function detectUserInstallations(options = {}) {
|
|
|
6973
7305
|
const roots = options.homeRoots ?? ["/home", "/root"];
|
|
6974
7306
|
const found = [];
|
|
6975
7307
|
for (const homeRoot of roots) {
|
|
6976
|
-
if (!(0,
|
|
6977
|
-
const homes = homeRoot === "/root" ? ["/root"] : (0,
|
|
7308
|
+
if (!(0, import_node_fs17.existsSync)(homeRoot)) continue;
|
|
7309
|
+
const homes = homeRoot === "/root" ? ["/root"] : (0, import_node_fs17.readdirSync)(homeRoot).map((entry2) => (0, import_node_path19.join)(homeRoot, entry2));
|
|
6978
7310
|
for (const home of homes) {
|
|
6979
7311
|
let stat;
|
|
6980
7312
|
try {
|
|
6981
|
-
stat = (0,
|
|
7313
|
+
stat = (0, import_node_fs17.lstatSync)(home);
|
|
6982
7314
|
} catch {
|
|
6983
7315
|
continue;
|
|
6984
7316
|
}
|
|
6985
7317
|
if (!stat.isDirectory()) continue;
|
|
6986
|
-
const unitDir = (0,
|
|
7318
|
+
const unitDir = (0, import_node_path19.join)(home, ".config", "systemd", "user");
|
|
6987
7319
|
let units = [];
|
|
6988
7320
|
try {
|
|
6989
|
-
units = (0,
|
|
7321
|
+
units = (0, import_node_fs17.readdirSync)(unitDir);
|
|
6990
7322
|
} catch {
|
|
6991
7323
|
units = [];
|
|
6992
7324
|
}
|
|
6993
7325
|
for (const unitName2 of units) {
|
|
6994
7326
|
if (!/^rigscope(?:-[0-9a-f]{12})?(?:-(?:hub|collector))?\.service$/.test(unitName2)) continue;
|
|
6995
|
-
const unitPath2 = (0,
|
|
7327
|
+
const unitPath2 = (0, import_node_path19.join)(unitDir, unitName2);
|
|
6996
7328
|
let execStart = null;
|
|
6997
7329
|
try {
|
|
6998
|
-
const line = (0,
|
|
7330
|
+
const line = (0, import_node_fs17.readFileSync)(unitPath2, "utf8").split("\n").find((item) => item.startsWith("ExecStart="));
|
|
6999
7331
|
execStart = line ? line.slice("ExecStart=".length) : null;
|
|
7000
7332
|
} catch {
|
|
7001
7333
|
}
|
|
7002
|
-
const stateCandidates = [(0,
|
|
7003
|
-
const stateDir = stateCandidates.find((candidate) => (0,
|
|
7004
|
-
found.push({ user: (0,
|
|
7334
|
+
const stateCandidates = [(0, import_node_path19.join)(home, ".local", "state", "rigscope")];
|
|
7335
|
+
const stateDir = stateCandidates.find((candidate) => (0, import_node_fs17.existsSync)(candidate)) ?? null;
|
|
7336
|
+
found.push({ user: (0, import_node_path19.basename)(home), home, unitPath: unitPath2, unitName: unitName2, execStart, stateDir });
|
|
7005
7337
|
}
|
|
7006
7338
|
}
|
|
7007
7339
|
}
|
|
@@ -7009,9 +7341,9 @@ function detectUserInstallations(options = {}) {
|
|
|
7009
7341
|
}
|
|
7010
7342
|
function lockIsLive(path2) {
|
|
7011
7343
|
try {
|
|
7012
|
-
const stat = (0,
|
|
7344
|
+
const stat = (0, import_node_fs17.lstatSync)(path2);
|
|
7013
7345
|
if (!stat.isFile() || stat.size > 4096) return { exists: true, live: false, pid: null, ambiguous: true };
|
|
7014
|
-
const owner = JSON.parse((0,
|
|
7346
|
+
const owner = JSON.parse((0, import_node_fs17.readFileSync)(path2, "utf8"));
|
|
7015
7347
|
const pid = owner.pid;
|
|
7016
7348
|
if (!Number.isSafeInteger(pid) || pid < 1) return { exists: true, live: false, pid: null, ambiguous: true };
|
|
7017
7349
|
try {
|
|
@@ -7029,9 +7361,9 @@ function lockIsLive(path2) {
|
|
|
7029
7361
|
}
|
|
7030
7362
|
function directoryLocks(directory) {
|
|
7031
7363
|
return [
|
|
7032
|
-
(0,
|
|
7033
|
-
(0,
|
|
7034
|
-
(0,
|
|
7364
|
+
(0, import_node_path19.join)(directory, "hub", "telemetry.sqlite.hub.lock"),
|
|
7365
|
+
(0, import_node_path19.join)(directory, "run", "rigscope.lock"),
|
|
7366
|
+
(0, import_node_path19.join)(directory, "collector", "collector-runtime.lock")
|
|
7035
7367
|
];
|
|
7036
7368
|
}
|
|
7037
7369
|
function assertDirectoryStopped(directory, scope = "local") {
|
|
@@ -7062,13 +7394,13 @@ function assertSystemStartAllowed(paths, components) {
|
|
|
7062
7394
|
}
|
|
7063
7395
|
function detectPowerDriver(moduleRoot = "/sys/module") {
|
|
7064
7396
|
const candidates = ["intel_rapl_msr", "intel_rapl_common", "intel_rapl_tpmi", "intel_rapl", "amd_energy"];
|
|
7065
|
-
return candidates.filter((name) => (0,
|
|
7397
|
+
return candidates.filter((name) => (0, import_node_fs17.existsSync)((0, import_node_path19.join)(moduleRoot, name)));
|
|
7066
7398
|
}
|
|
7067
7399
|
function readPasswd(path2 = "/etc/passwd") {
|
|
7068
7400
|
const users = /* @__PURE__ */ new Map();
|
|
7069
7401
|
let lines;
|
|
7070
7402
|
try {
|
|
7071
|
-
lines = (0,
|
|
7403
|
+
lines = (0, import_node_fs17.readFileSync)(path2, "utf8").split("\n");
|
|
7072
7404
|
} catch {
|
|
7073
7405
|
return users;
|
|
7074
7406
|
}
|
|
@@ -7085,7 +7417,7 @@ function readGroups(path2 = "/etc/group") {
|
|
|
7085
7417
|
const groups = /* @__PURE__ */ new Map();
|
|
7086
7418
|
let lines;
|
|
7087
7419
|
try {
|
|
7088
|
-
lines = (0,
|
|
7420
|
+
lines = (0, import_node_fs17.readFileSync)(path2, "utf8").split("\n");
|
|
7089
7421
|
} catch {
|
|
7090
7422
|
return groups;
|
|
7091
7423
|
}
|
|
@@ -7113,7 +7445,7 @@ function inspectPowerAccess(options = {}) {
|
|
|
7113
7445
|
const sysusers = options.sysusersPath ?? powerSysusersPath(paths);
|
|
7114
7446
|
let ruleText = null;
|
|
7115
7447
|
try {
|
|
7116
|
-
ruleText = (0,
|
|
7448
|
+
ruleText = (0, import_node_fs17.readFileSync)(rulePath, "utf8");
|
|
7117
7449
|
} catch {
|
|
7118
7450
|
ruleText = null;
|
|
7119
7451
|
}
|
|
@@ -7130,27 +7462,27 @@ function inspectPowerAccess(options = {}) {
|
|
|
7130
7462
|
const domains = [];
|
|
7131
7463
|
let entries = [];
|
|
7132
7464
|
try {
|
|
7133
|
-
entries = (0,
|
|
7465
|
+
entries = (0, import_node_fs17.readdirSync)(paths.powercapRoot);
|
|
7134
7466
|
} catch {
|
|
7135
7467
|
entries = [];
|
|
7136
7468
|
}
|
|
7137
7469
|
for (const entry2 of entries.filter((name) => /^intel-rapl:\d+$/.test(name)).sort()) {
|
|
7138
|
-
const domainPath = (0,
|
|
7470
|
+
const domainPath = (0, import_node_path19.join)(paths.powercapRoot, entry2);
|
|
7139
7471
|
let name = entry2;
|
|
7140
7472
|
try {
|
|
7141
|
-
name = (0,
|
|
7473
|
+
name = (0, import_node_fs17.readFileSync)((0, import_node_path19.join)(domainPath, "name"), "utf8").trim() || entry2;
|
|
7142
7474
|
} catch {
|
|
7143
7475
|
}
|
|
7144
7476
|
if (!/^package/.test(name)) continue;
|
|
7145
|
-
const energyPath = (0,
|
|
7146
|
-
const maxRangePath = (0,
|
|
7477
|
+
const energyPath = (0, import_node_path19.join)(domainPath, "energy_uj");
|
|
7478
|
+
const maxRangePath = (0, import_node_path19.join)(domainPath, "max_energy_range_uj");
|
|
7147
7479
|
const readStat = (path2) => {
|
|
7148
7480
|
if (options.statOverride) {
|
|
7149
7481
|
const override = options.statOverride(path2);
|
|
7150
7482
|
return override === null ? null : { mode: modeString(override.mode), uid: override.uid, gid: override.gid };
|
|
7151
7483
|
}
|
|
7152
7484
|
try {
|
|
7153
|
-
const stat = (0,
|
|
7485
|
+
const stat = (0, import_node_fs17.statSync)(path2);
|
|
7154
7486
|
return { mode: modeString(stat.mode), uid: stat.uid, gid: stat.gid };
|
|
7155
7487
|
} catch {
|
|
7156
7488
|
return null;
|
|
@@ -7184,7 +7516,7 @@ function inspectPowerAccess(options = {}) {
|
|
|
7184
7516
|
problems.push(`collector account ${accounts.collector} is not a member of ${accounts.powerGroup}`);
|
|
7185
7517
|
}
|
|
7186
7518
|
if (!compliant) problems.push(`persistent udev rule is missing or not compliant: ${rulePath}`);
|
|
7187
|
-
if (!(0,
|
|
7519
|
+
if (!(0, import_node_fs17.existsSync)(sysusers)) problems.push(`power sysusers definition is missing: ${sysusers}`);
|
|
7188
7520
|
for (const domain of domains) {
|
|
7189
7521
|
if (!domain.energyExists) problems.push(`${domain.name}: energy_uj is unavailable`);
|
|
7190
7522
|
else if (domain.energy?.worldReadable) problems.push(`${domain.name}: energy_uj is world-readable`);
|
|
@@ -7203,7 +7535,7 @@ function inspectPowerAccess(options = {}) {
|
|
|
7203
7535
|
collectorGids,
|
|
7204
7536
|
group: { name: accounts.powerGroup, exists: group !== null, gid: group?.gid ?? null, members: group?.members ?? [] },
|
|
7205
7537
|
rule: { path: rulePath, present: ruleText !== null, compliant },
|
|
7206
|
-
sysusers: { path: sysusers, present: (0,
|
|
7538
|
+
sysusers: { path: sysusers, present: (0, import_node_fs17.existsSync)(sysusers) },
|
|
7207
7539
|
collectorCanRead,
|
|
7208
7540
|
persistent: compliant && group !== null && collector !== null && group.members.includes(accounts.collector),
|
|
7209
7541
|
worldReadable,
|
|
@@ -7212,14 +7544,14 @@ function inspectPowerAccess(options = {}) {
|
|
|
7212
7544
|
};
|
|
7213
7545
|
}
|
|
7214
7546
|
async function backupDatabase2(source, output, host) {
|
|
7215
|
-
ensureDirectory((0,
|
|
7547
|
+
ensureDirectory((0, import_node_path19.dirname)(output), 448, true);
|
|
7216
7548
|
const db = new import_node_sqlite4.DatabaseSync(source, { readOnly: true, timeout: 5e3 });
|
|
7217
7549
|
try {
|
|
7218
7550
|
await (0, import_node_sqlite4.backup)(db, output);
|
|
7219
7551
|
} finally {
|
|
7220
7552
|
db.close();
|
|
7221
7553
|
}
|
|
7222
|
-
(0,
|
|
7554
|
+
(0, import_node_fs17.chmodSync)(output, 384);
|
|
7223
7555
|
const check = new import_node_sqlite4.DatabaseSync(output, { readOnly: true });
|
|
7224
7556
|
try {
|
|
7225
7557
|
const result = check.prepare("PRAGMA integrity_check").get();
|
|
@@ -7230,7 +7562,7 @@ async function backupDatabase2(source, output, host) {
|
|
|
7230
7562
|
void host;
|
|
7231
7563
|
}
|
|
7232
7564
|
function databaseSchema(path2) {
|
|
7233
|
-
if (!(0,
|
|
7565
|
+
if (!(0, import_node_fs17.existsSync)(path2)) return null;
|
|
7234
7566
|
const db = new import_node_sqlite4.DatabaseSync(path2, { readOnly: true, timeout: 5e3 });
|
|
7235
7567
|
try {
|
|
7236
7568
|
const table = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='schema_migrations'").get();
|
|
@@ -7249,28 +7581,28 @@ function replaceDatabaseFromBackup(backupPath, target, safetyBackup, host) {
|
|
|
7249
7581
|
} finally {
|
|
7250
7582
|
backup3.close();
|
|
7251
7583
|
}
|
|
7252
|
-
ensureDirectory((0,
|
|
7253
|
-
if (safetyBackup !== null && (0,
|
|
7584
|
+
ensureDirectory((0, import_node_path19.dirname)(target), 448, true);
|
|
7585
|
+
if (safetyBackup !== null && (0, import_node_fs17.existsSync)(target)) {
|
|
7254
7586
|
void host;
|
|
7255
7587
|
}
|
|
7256
|
-
const temporary = (0,
|
|
7257
|
-
(0,
|
|
7258
|
-
(0,
|
|
7588
|
+
const temporary = (0, import_node_path19.join)((0, import_node_path19.dirname)(target), `.restore-${process.pid}-${Date.now()}.sqlite`);
|
|
7589
|
+
(0, import_node_fs17.copyFileSync)(backupPath, temporary);
|
|
7590
|
+
(0, import_node_fs17.chmodSync)(temporary, 384);
|
|
7259
7591
|
for (const sidecar of [`${target}-wal`, `${target}-shm`]) {
|
|
7260
7592
|
try {
|
|
7261
|
-
(0,
|
|
7593
|
+
(0, import_node_fs17.unlinkSync)(sidecar);
|
|
7262
7594
|
} catch {
|
|
7263
7595
|
}
|
|
7264
7596
|
}
|
|
7265
|
-
(0,
|
|
7266
|
-
(0,
|
|
7597
|
+
(0, import_node_fs17.renameSync)(temporary, target);
|
|
7598
|
+
(0, import_node_fs17.chmodSync)(target, 384);
|
|
7267
7599
|
}
|
|
7268
7600
|
function newestTimestamp() {
|
|
7269
7601
|
return (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
7270
7602
|
}
|
|
7271
7603
|
function adoptUserState(options) {
|
|
7272
|
-
const source = (0,
|
|
7273
|
-
if (!(0,
|
|
7604
|
+
const source = (0, import_node_path19.resolve)(options.source);
|
|
7605
|
+
if (!(0, import_node_fs17.existsSync)(source)) throw new SystemError("invalid-adoption", `user installation does not exist: ${source}`);
|
|
7274
7606
|
if (isWithin(options.paths.prefix, source) || isWithin(options.paths.stateDir, source) || isWithin(source, options.paths.stateDir)) {
|
|
7275
7607
|
throw new SystemError("invalid-adoption", "adoption source and system paths must not overlap");
|
|
7276
7608
|
}
|
|
@@ -7280,8 +7612,8 @@ function adoptUserState(options) {
|
|
|
7280
7612
|
const { port, origin } = setup;
|
|
7281
7613
|
if (!Number.isInteger(port) || port < 1 || port > 65535) throw new SystemError("invalid-adoption", "adopted hub port is invalid");
|
|
7282
7614
|
if (options.role !== "collector") {
|
|
7283
|
-
const sourceDatabase = (0,
|
|
7284
|
-
if ((0,
|
|
7615
|
+
const sourceDatabase = (0, import_node_path19.join)(source, "hub", "telemetry.sqlite");
|
|
7616
|
+
if ((0, import_node_fs17.existsSync)(sourceDatabase)) {
|
|
7285
7617
|
assertPrivateSourceFile(sourceDatabase, "adopted database");
|
|
7286
7618
|
const database = new import_node_sqlite4.DatabaseSync(sourceDatabase, { readOnly: true });
|
|
7287
7619
|
try {
|
|
@@ -7291,12 +7623,12 @@ function adoptUserState(options) {
|
|
|
7291
7623
|
database.close();
|
|
7292
7624
|
}
|
|
7293
7625
|
}
|
|
7294
|
-
const sourceEnrollment = (0,
|
|
7295
|
-
if ((0,
|
|
7626
|
+
const sourceEnrollment = (0, import_node_path19.join)(source, "hub", "enrollment.json");
|
|
7627
|
+
if ((0, import_node_fs17.existsSync)(sourceEnrollment)) assertPrivateSourceFile(sourceEnrollment, "adopted enrollment");
|
|
7296
7628
|
}
|
|
7297
7629
|
if (options.role !== "hub") {
|
|
7298
|
-
const sourceCollectorState = (0,
|
|
7299
|
-
if ((0,
|
|
7630
|
+
const sourceCollectorState = (0, import_node_path19.join)(source, "collector", "state.json");
|
|
7631
|
+
if ((0, import_node_fs17.existsSync)(sourceCollectorState)) {
|
|
7300
7632
|
assertPrivateSourceFile(sourceCollectorState, "adopted collector state");
|
|
7301
7633
|
readCollectorIdentity(sourceCollectorState);
|
|
7302
7634
|
}
|
|
@@ -7305,7 +7637,7 @@ function adoptUserState(options) {
|
|
|
7305
7637
|
const warnings = [];
|
|
7306
7638
|
const targetDatabase = hubDatabasePath(options.paths);
|
|
7307
7639
|
const targetCollector = collectorStatePath2(options.paths);
|
|
7308
|
-
if (options.apply && (0,
|
|
7640
|
+
if (options.apply && (0, import_node_fs17.existsSync)(targetDatabase)) {
|
|
7309
7641
|
throw new SystemError("destination-exists", `refusing to overwrite ${targetDatabase}`);
|
|
7310
7642
|
}
|
|
7311
7643
|
const hubEnv = options.role === "collector" ? null : [
|
|
@@ -7340,62 +7672,42 @@ function adoptUserState(options) {
|
|
|
7340
7672
|
port
|
|
7341
7673
|
};
|
|
7342
7674
|
}
|
|
7343
|
-
function copyAdoptedTree(source, target, copied, skipLocks = true) {
|
|
7344
|
-
const visit = (current, destination) => {
|
|
7345
|
-
const stat = (0, import_node_fs16.lstatSync)(current);
|
|
7346
|
-
if (stat.isSymbolicLink()) return;
|
|
7347
|
-
if (stat.isDirectory()) {
|
|
7348
|
-
(0, import_node_fs16.mkdirSync)(destination, { recursive: true, mode: 448 });
|
|
7349
|
-
for (const entry2 of (0, import_node_fs16.readdirSync)(current)) visit((0, import_node_path18.join)(current, entry2), (0, import_node_path18.join)(destination, entry2));
|
|
7350
|
-
return;
|
|
7351
|
-
}
|
|
7352
|
-
if (!stat.isFile()) return;
|
|
7353
|
-
if (skipLocks && /\.(lock|sock)$/.test(current)) return;
|
|
7354
|
-
(0, import_node_fs16.mkdirSync)((0, import_node_path18.dirname)(destination), { recursive: true, mode: 448 });
|
|
7355
|
-
(0, import_node_fs16.copyFileSync)(current, destination);
|
|
7356
|
-
(0, import_node_fs16.chmodSync)(destination, 384);
|
|
7357
|
-
copied.push({ source: current, target: destination, sha256: sha256File2(destination), bytes: stat.size });
|
|
7358
|
-
};
|
|
7359
|
-
visit(source, target);
|
|
7360
|
-
}
|
|
7361
7675
|
async function performAdoptionCopyAsync(options) {
|
|
7362
7676
|
const { source, paths, role, host, copy } = options;
|
|
7363
7677
|
assertDirectoryStopped(source, role);
|
|
7364
7678
|
const targetDatabase = hubDatabasePath(paths);
|
|
7365
|
-
const sourceDatabase = (0,
|
|
7366
|
-
if (role !== "collector" && (0,
|
|
7679
|
+
const sourceDatabase = (0, import_node_path19.join)(source, "hub", "telemetry.sqlite");
|
|
7680
|
+
if (role !== "collector" && (0, import_node_fs17.existsSync)(sourceDatabase) && !(0, import_node_fs17.existsSync)(targetDatabase)) {
|
|
7367
7681
|
assertPrivateSourceFile(sourceDatabase, "adopted database");
|
|
7368
|
-
ensureDirectory((0,
|
|
7682
|
+
ensureDirectory((0, import_node_path19.join)(paths.stateDir, "hub"), 448, true);
|
|
7369
7683
|
await backupDatabase2(sourceDatabase, targetDatabase, host);
|
|
7370
7684
|
copy.record.files.push({
|
|
7371
7685
|
source: sourceDatabase,
|
|
7372
7686
|
target: targetDatabase,
|
|
7373
7687
|
sha256: sha256File2(targetDatabase),
|
|
7374
|
-
bytes: (0,
|
|
7688
|
+
bytes: (0, import_node_fs17.statSync)(targetDatabase).size
|
|
7375
7689
|
});
|
|
7376
7690
|
}
|
|
7377
|
-
const sourceCollectorState = (0,
|
|
7378
|
-
if (role !== "hub" && (0,
|
|
7691
|
+
const sourceCollectorState = (0, import_node_path19.join)(source, "collector", "state.json");
|
|
7692
|
+
if (role !== "hub" && (0, import_node_fs17.existsSync)(sourceCollectorState)) {
|
|
7379
7693
|
assertPrivateSourceFile(sourceCollectorState, "adopted collector state");
|
|
7380
|
-
ensureDirectory((0,
|
|
7694
|
+
ensureDirectory((0, import_node_path19.join)(paths.stateDir, "collector"), 448, true);
|
|
7381
7695
|
const targetCollector = collectorStatePath2(paths);
|
|
7382
|
-
(0,
|
|
7383
|
-
(0,
|
|
7696
|
+
(0, import_node_fs17.copyFileSync)(sourceCollectorState, targetCollector);
|
|
7697
|
+
(0, import_node_fs17.chmodSync)(targetCollector, 384);
|
|
7384
7698
|
copy.record.files.push({
|
|
7385
7699
|
source: sourceCollectorState,
|
|
7386
7700
|
target: targetCollector,
|
|
7387
7701
|
sha256: sha256File2(targetCollector),
|
|
7388
|
-
bytes: (0,
|
|
7702
|
+
bytes: (0, import_node_fs17.statSync)(targetCollector).size
|
|
7389
7703
|
});
|
|
7390
|
-
const outbox = (0, import_node_path18.join)(source, "collector", "outbox");
|
|
7391
|
-
if ((0, import_node_fs16.existsSync)(outbox)) copyAdoptedTree(outbox, (0, import_node_path18.join)(paths.stateDir, "collector", "outbox"), copy.record.files);
|
|
7392
7704
|
}
|
|
7393
|
-
const enrollment = (0,
|
|
7394
|
-
if (role !== "collector" && (0,
|
|
7705
|
+
const enrollment = (0, import_node_path19.join)(source, "hub", "enrollment.json");
|
|
7706
|
+
if (role !== "collector" && (0, import_node_fs17.existsSync)(enrollment)) {
|
|
7395
7707
|
const target = hubEnrollmentPath(paths);
|
|
7396
|
-
(0,
|
|
7397
|
-
(0,
|
|
7398
|
-
copy.record.files.push({ source: enrollment, target, sha256: sha256File2(target), bytes: (0,
|
|
7708
|
+
(0, import_node_fs17.copyFileSync)(enrollment, target);
|
|
7709
|
+
(0, import_node_fs17.chmodSync)(target, 384);
|
|
7710
|
+
copy.record.files.push({ source: enrollment, target, sha256: sha256File2(target), bytes: (0, import_node_fs17.statSync)(target).size });
|
|
7399
7711
|
}
|
|
7400
7712
|
}
|
|
7401
7713
|
function writeSysusersFiles(paths, accounts, role, power, host) {
|
|
@@ -7435,15 +7747,15 @@ function writePowerRule(paths, accounts) {
|
|
|
7435
7747
|
writeManagedFile(raplRulePath(paths), renderRaplRule(accounts), 420, true);
|
|
7436
7748
|
}
|
|
7437
7749
|
function powerOriginalPath(paths) {
|
|
7438
|
-
return (0,
|
|
7750
|
+
return (0, import_node_path19.join)(paths.stateDir, POWER_STATE_FILE_NAME);
|
|
7439
7751
|
}
|
|
7440
7752
|
function capturePowerOriginals(paths) {
|
|
7441
7753
|
const files = {};
|
|
7442
7754
|
for (const domain of packageDomainPaths(paths.powercapRoot)) {
|
|
7443
7755
|
for (const name of ["energy_uj", "max_energy_range_uj"]) {
|
|
7444
|
-
const path2 = (0,
|
|
7756
|
+
const path2 = (0, import_node_path19.join)(domain, name);
|
|
7445
7757
|
try {
|
|
7446
|
-
const stat = (0,
|
|
7758
|
+
const stat = (0, import_node_fs17.statSync)(path2);
|
|
7447
7759
|
files[path2] = { mode: stat.mode & 511, uid: stat.uid, gid: stat.gid };
|
|
7448
7760
|
} catch {
|
|
7449
7761
|
}
|
|
@@ -7455,8 +7767,8 @@ function capturePowerOriginals(paths) {
|
|
|
7455
7767
|
function applyPowerAccess(paths, accounts, host) {
|
|
7456
7768
|
for (const domain of packageDomainPaths(paths.powercapRoot)) {
|
|
7457
7769
|
for (const name of ["energy_uj", "max_energy_range_uj"]) {
|
|
7458
|
-
const path2 = (0,
|
|
7459
|
-
if (!(0,
|
|
7770
|
+
const path2 = (0, import_node_path19.join)(domain, name);
|
|
7771
|
+
if (!(0, import_node_fs17.existsSync)(path2)) continue;
|
|
7460
7772
|
runRequired(host, "chgrp", [accounts.powerGroup, path2], `power counter group ${path2}`);
|
|
7461
7773
|
runRequired(host, "chmod", ["0440", path2], `power counter mode ${path2}`);
|
|
7462
7774
|
}
|
|
@@ -7469,9 +7781,9 @@ function resumePowerRule(paths, host) {
|
|
|
7469
7781
|
}
|
|
7470
7782
|
function packageDomainPaths(root) {
|
|
7471
7783
|
try {
|
|
7472
|
-
return (0,
|
|
7784
|
+
return (0, import_node_fs17.readdirSync)(root).filter((entry2) => /^intel-rapl:\d+$/.test(entry2)).map((entry2) => (0, import_node_path19.join)(root, entry2)).filter((path2) => {
|
|
7473
7785
|
try {
|
|
7474
|
-
return /^package/.test((0,
|
|
7786
|
+
return /^package/.test((0, import_node_fs17.readFileSync)((0, import_node_path19.join)(path2, "name"), "utf8").trim());
|
|
7475
7787
|
} catch {
|
|
7476
7788
|
return false;
|
|
7477
7789
|
}
|
|
@@ -7491,8 +7803,8 @@ function restorePowerOriginals(paths, host) {
|
|
|
7491
7803
|
const files = { ...originals?.files ?? {} };
|
|
7492
7804
|
for (const domain of packageDomainPaths(paths.powercapRoot)) {
|
|
7493
7805
|
for (const name of ["energy_uj", "max_energy_range_uj"]) {
|
|
7494
|
-
const path2 = (0,
|
|
7495
|
-
if (!(0,
|
|
7806
|
+
const path2 = (0, import_node_path19.join)(domain, name);
|
|
7807
|
+
if (!(0, import_node_fs17.existsSync)(path2)) continue;
|
|
7496
7808
|
const original = files[path2];
|
|
7497
7809
|
if (original) {
|
|
7498
7810
|
runRequired(host, "chown", [`${original.uid}:${original.gid}`, path2], "restore counter ownership");
|
|
@@ -7508,7 +7820,7 @@ function restorePowerOriginals(paths, host) {
|
|
|
7508
7820
|
}
|
|
7509
7821
|
}
|
|
7510
7822
|
try {
|
|
7511
|
-
(0,
|
|
7823
|
+
(0, import_node_fs17.unlinkSync)(powerOriginalPath(paths));
|
|
7512
7824
|
} catch {
|
|
7513
7825
|
}
|
|
7514
7826
|
return restored;
|
|
@@ -7532,7 +7844,7 @@ function stopUnits(host, units) {
|
|
|
7532
7844
|
if (units.some((unit) => systemdActive(host, unit))) throw new SystemError("service-active", "system services did not stop; no files were restored");
|
|
7533
7845
|
}
|
|
7534
7846
|
function unitsForCleanup(paths, host) {
|
|
7535
|
-
const legacy = LEGACY_UNIT_NAMES.filter((unit) => (0,
|
|
7847
|
+
const legacy = LEGACY_UNIT_NAMES.filter((unit) => (0, import_node_fs17.existsSync)((0, import_node_path19.join)(paths.unitsDir, unit)) || systemdActive(host, unit));
|
|
7536
7848
|
return [...Object.values(UNIT_NAMES), ...legacy];
|
|
7537
7849
|
}
|
|
7538
7850
|
function startUnits(host, units) {
|
|
@@ -7570,7 +7882,7 @@ async function verifySystemHealth(paths, state, host, timeoutMs, components = en
|
|
|
7570
7882
|
const report = runRequired(
|
|
7571
7883
|
host,
|
|
7572
7884
|
state.nodePath,
|
|
7573
|
-
[(0,
|
|
7885
|
+
[(0, import_node_path19.join)(paths.prefix, "current/dist/ops.cjs"), "inspect", "--database", hubDatabasePath(paths), "--json"],
|
|
7574
7886
|
"activated database verification",
|
|
7575
7887
|
{ timeoutMs: Math.max(100, deadline - Date.now()) }
|
|
7576
7888
|
);
|
|
@@ -7586,8 +7898,8 @@ async function verifySystemHealth(paths, state, host, timeoutMs, components = en
|
|
|
7586
7898
|
let problem = "no sampling marker";
|
|
7587
7899
|
while (Date.now() < deadline) {
|
|
7588
7900
|
try {
|
|
7589
|
-
const marker = readJsonObject((0,
|
|
7590
|
-
const lease = readJsonObject((0,
|
|
7901
|
+
const marker = readJsonObject((0, import_node_path19.join)(paths.stateDir, "collector/health.json"));
|
|
7902
|
+
const lease = readJsonObject((0, import_node_path19.join)(paths.stateDir, "collector/collector-runtime.lock"));
|
|
7591
7903
|
if (marker.pid !== lease.pid || !Number.isSafeInteger(marker.pid)) throw new Error("sampling marker belongs to another process");
|
|
7592
7904
|
process.kill(Number(marker.pid), 0);
|
|
7593
7905
|
if (marker.version !== state.currentVersion || !Number.isFinite(marker.sampledAt) || Date.now() - Number(marker.sampledAt) > 15e3) throw new Error("collector version or sampling freshness is wrong");
|
|
@@ -7602,12 +7914,12 @@ async function verifySystemHealth(paths, state, host, timeoutMs, components = en
|
|
|
7602
7914
|
}
|
|
7603
7915
|
function chownAccount(paths, owner, group, host) {
|
|
7604
7916
|
for (const path2 of paths) {
|
|
7605
|
-
if (!(0,
|
|
7917
|
+
if (!(0, import_node_fs17.existsSync)(path2)) continue;
|
|
7606
7918
|
runRequired(host, "chown", ["-R", `${owner}:${group}`, path2], `ownership ${path2}`);
|
|
7607
7919
|
}
|
|
7608
7920
|
}
|
|
7609
7921
|
function chmodTree(path2, host) {
|
|
7610
|
-
if (!(0,
|
|
7922
|
+
if (!(0, import_node_fs17.existsSync)(path2)) return;
|
|
7611
7923
|
runRequired(host, "chmod", ["-R", "u=rwX,go=rX", path2], `release permissions ${path2}`);
|
|
7612
7924
|
}
|
|
7613
7925
|
function pickRollbackBackup(state, previousSchema) {
|
|
@@ -7618,9 +7930,12 @@ function pickRollbackBackup(state, previousSchema) {
|
|
|
7618
7930
|
async function recoverFailedUpgrade(options) {
|
|
7619
7931
|
stopUnits(options.host, options.units);
|
|
7620
7932
|
assertDirectoryStopped(options.paths.stateDir);
|
|
7621
|
-
|
|
7622
|
-
|
|
7623
|
-
|
|
7933
|
+
for (const message of undoMachineDataCleanup(systemMachineDataPaths(options.paths), options.machineData?.stagedQueues ?? null)) {
|
|
7934
|
+
console.warn(`rigscope system upgrade recovery: ${message}`);
|
|
7935
|
+
}
|
|
7936
|
+
replaceSymlink((0, import_node_path19.join)(options.paths.prefix, "current"), options.oldCurrent, options.host);
|
|
7937
|
+
if (options.oldPrevious === null) removeSymlink((0, import_node_path19.join)(options.paths.prefix, "previous"));
|
|
7938
|
+
else replaceSymlink((0, import_node_path19.join)(options.paths.prefix, "previous"), options.oldPrevious, options.host);
|
|
7624
7939
|
const database = hubDatabasePath(options.paths);
|
|
7625
7940
|
let afterSchema = null;
|
|
7626
7941
|
try {
|
|
@@ -7628,13 +7943,13 @@ async function recoverFailedUpgrade(options) {
|
|
|
7628
7943
|
} catch {
|
|
7629
7944
|
afterSchema = null;
|
|
7630
7945
|
}
|
|
7631
|
-
if (options.backupPath !== null && (0,
|
|
7632
|
-
await backupDatabase2(database, (0,
|
|
7946
|
+
if (options.backupPath !== null && (0, import_node_fs17.existsSync)(options.backupPath) && (afterSchema === null || options.beforeSchema === null || afterSchema > options.beforeSchema || options.machineData?.databaseCleared === true)) {
|
|
7947
|
+
await backupDatabase2(database, (0, import_node_path19.join)(options.paths.stateDir, "backups", `failed-upgrade-${newestTimestamp()}.sqlite`), options.host);
|
|
7633
7948
|
replaceDatabaseFromBackup(options.backupPath, database, null, options.host);
|
|
7634
7949
|
runRequired(options.host, "chown", [`${options.state.accounts.hub}:${options.state.accounts.hub}`, database], "restored database ownership");
|
|
7635
7950
|
}
|
|
7636
|
-
options.state.previousVersion = options.oldPrevious === null ? null : (0,
|
|
7637
|
-
options.state.currentVersion = (0,
|
|
7951
|
+
options.state.previousVersion = options.oldPrevious === null ? null : (0, import_node_path19.basename)(options.oldPrevious);
|
|
7952
|
+
options.state.currentVersion = (0, import_node_path19.basename)(options.oldCurrent);
|
|
7638
7953
|
writeSystemState(options.paths, options.state);
|
|
7639
7954
|
if (options.activeComponents.length > 0) {
|
|
7640
7955
|
startUnits(options.host, options.units);
|
|
@@ -7643,14 +7958,14 @@ async function recoverFailedUpgrade(options) {
|
|
|
7643
7958
|
}
|
|
7644
7959
|
function assertManagedFileOwnership(paths, path2) {
|
|
7645
7960
|
if (!isDefaultSystemLayout(paths)) return;
|
|
7646
|
-
if (!(0,
|
|
7647
|
-
const stat = (0,
|
|
7961
|
+
if (!(0, import_node_fs17.existsSync)(path2)) return;
|
|
7962
|
+
const stat = (0, import_node_fs17.lstatSync)(path2);
|
|
7648
7963
|
if (stat.isSymbolicLink() || !stat.isFile()) throw new SystemError("unsafe-path", `${path2} must be a regular managed file`);
|
|
7649
7964
|
if (stat.uid !== 0) throw new SystemError("insecure-ownership", `${path2} must be root-owned before replacement`);
|
|
7650
7965
|
if ((stat.mode & 18) !== 0) throw new SystemError("insecure-permissions", `${path2} must not be group/world-writable`);
|
|
7651
7966
|
}
|
|
7652
7967
|
function writeUnitFile(paths, unit, content, replace) {
|
|
7653
|
-
const path2 = (0,
|
|
7968
|
+
const path2 = (0, import_node_path19.join)(paths.unitsDir, unit);
|
|
7654
7969
|
assertManagedFileOwnership(paths, path2);
|
|
7655
7970
|
writeManagedFile(path2, content, 420, replace);
|
|
7656
7971
|
}
|
|
@@ -7665,19 +7980,19 @@ function ensureComponentSetup(options) {
|
|
|
7665
7980
|
ensureDirectory(paths.configDir, 493);
|
|
7666
7981
|
ensureDirectory(paths.stateDir, 493);
|
|
7667
7982
|
ensureDirectory(paths.unitsDir, 493);
|
|
7668
|
-
ensureDirectory((0,
|
|
7669
|
-
ensureDirectory((0,
|
|
7670
|
-
ensureDirectory((0,
|
|
7671
|
-
ensureDirectory((0,
|
|
7983
|
+
ensureDirectory((0, import_node_path19.join)(paths.stateDir, "hub"), 448, true);
|
|
7984
|
+
ensureDirectory((0, import_node_path19.join)(paths.stateDir, "hub", "run"), 448, true);
|
|
7985
|
+
ensureDirectory((0, import_node_path19.join)(paths.stateDir, "collector"), 448, true);
|
|
7986
|
+
ensureDirectory((0, import_node_path19.join)(paths.stateDir, "backups"), 448, true);
|
|
7672
7987
|
const release = currentReleaseOrThrow(paths);
|
|
7673
7988
|
void release;
|
|
7674
7989
|
writeSysusersFiles(paths, accounts, "local", power, host);
|
|
7675
7990
|
if (component === "hub") {
|
|
7676
|
-
if (!(0,
|
|
7991
|
+
if (!(0, import_node_fs17.existsSync)(hubEnvPath(paths))) {
|
|
7677
7992
|
const env = hubEnvTemplate(paths);
|
|
7678
7993
|
writeManagedFile(hubEnvPath(paths), env, 384, false);
|
|
7679
7994
|
}
|
|
7680
|
-
if (!(0,
|
|
7995
|
+
if (!(0, import_node_fs17.existsSync)((0, import_node_path19.join)(paths.unitsDir, UNIT_NAMES.hub))) {
|
|
7681
7996
|
const env = readHubEnvironment(paths);
|
|
7682
7997
|
const remote = env.HUB_PUBLIC_ORIGIN !== void 0 && env.HUB_PUBLIC_ORIGIN !== "";
|
|
7683
7998
|
const unit = renderSystemHubUnit({
|
|
@@ -7694,7 +8009,7 @@ function ensureComponentSetup(options) {
|
|
|
7694
8009
|
`, false);
|
|
7695
8010
|
}
|
|
7696
8011
|
} else {
|
|
7697
|
-
if (!(0,
|
|
8012
|
+
if (!(0, import_node_fs17.existsSync)(collectorEnvPath(paths))) {
|
|
7698
8013
|
writeManagedFile(collectorEnvPath(paths), collectorEnvTemplate(), 384, false);
|
|
7699
8014
|
}
|
|
7700
8015
|
const unit = renderSystemCollectorUnit({
|
|
@@ -7710,17 +8025,17 @@ function ensureComponentSetup(options) {
|
|
|
7710
8025
|
const validation = runRequired(
|
|
7711
8026
|
host,
|
|
7712
8027
|
"systemd-analyze",
|
|
7713
|
-
["verify", "--man=no", (0,
|
|
8028
|
+
["verify", "--man=no", (0, import_node_path19.join)(paths.unitsDir, unitFor(component))],
|
|
7714
8029
|
"native systemd unit validation"
|
|
7715
8030
|
);
|
|
7716
8031
|
if (/path is not absolute|bad unit file|fatal error|unknown (?:key|lvalue)|ignoring/i.test(validation.stderr)) {
|
|
7717
8032
|
throw new SystemError("invalid-unit", "native systemd validation rejected a generated directive");
|
|
7718
8033
|
}
|
|
7719
|
-
if (component === "hub") chownAccount([(0,
|
|
7720
|
-
if (component === "collector") chownAccount([(0,
|
|
8034
|
+
if (component === "hub") chownAccount([(0, import_node_path19.join)(paths.stateDir, "hub")], accounts.hub, accounts.hub, host);
|
|
8035
|
+
if (component === "collector") chownAccount([(0, import_node_path19.join)(paths.stateDir, "collector")], accounts.collector, accounts.collector, host);
|
|
7721
8036
|
}
|
|
7722
8037
|
function ensurePowerAccess(paths, accounts, host) {
|
|
7723
|
-
if (!(0,
|
|
8038
|
+
if (!(0, import_node_fs17.existsSync)(powerOriginalPath(paths))) capturePowerOriginals(paths);
|
|
7724
8039
|
writePowerRule(paths, accounts);
|
|
7725
8040
|
resumePowerRule(paths, host);
|
|
7726
8041
|
applyPowerAccess(paths, accounts, host);
|
|
@@ -7738,7 +8053,7 @@ function resetUnfinishedSystemState(options) {
|
|
|
7738
8053
|
}
|
|
7739
8054
|
function installPreset(options, role) {
|
|
7740
8055
|
if (options.adoptFrom !== void 0) {
|
|
7741
|
-
return componentSet(readAdoptionSetup((0,
|
|
8056
|
+
return componentSet(readAdoptionSetup((0, import_node_path19.resolve)(options.adoptFrom)).components);
|
|
7742
8057
|
}
|
|
7743
8058
|
return componentsForRole(role);
|
|
7744
8059
|
}
|
|
@@ -7750,11 +8065,11 @@ function planSystemInstall(options) {
|
|
|
7750
8065
|
const power = options.power !== false && preset.collector;
|
|
7751
8066
|
const initial = options.enable === true ? preset : { hub: false, collector: false };
|
|
7752
8067
|
const files = [
|
|
7753
|
-
{ path: (0,
|
|
8068
|
+
{ path: (0, import_node_path19.join)(paths.prefix, "current"), mode: "symlink", purpose: "active root-owned release" },
|
|
7754
8069
|
{ path: hubEnvPath(paths), mode: "0600", purpose: "root-owned hub configuration" },
|
|
7755
8070
|
{ path: collectorEnvPath(paths), mode: "0600", purpose: "root-owned collector configuration" },
|
|
7756
8071
|
{ path: sysusersPath(paths), mode: "0644", purpose: "dedicated nologin accounts" },
|
|
7757
|
-
...COMPONENTS3.map((component) => ({ path: (0,
|
|
8072
|
+
...COMPONENTS3.map((component) => ({ path: (0, import_node_path19.join)(paths.unitsDir, unitFor(component)), mode: "0644", purpose: `${component} boot unit` }))
|
|
7758
8073
|
];
|
|
7759
8074
|
if (power) {
|
|
7760
8075
|
files.push({ path: raplRulePath(paths), mode: "0644", purpose: "package RAPL read rule" });
|
|
@@ -7769,7 +8084,7 @@ function planSystemInstall(options) {
|
|
|
7769
8084
|
];
|
|
7770
8085
|
const notes = [
|
|
7771
8086
|
"Nothing is changed without --apply and root.",
|
|
7772
|
-
options.adoptFrom ? `Adopts ${(0,
|
|
8087
|
+
options.adoptFrom ? `Adopts ${(0, import_node_path19.resolve)(options.adoptFrom)} by copy only; the original user setup is preserved.` : "Existing user services are not modified.",
|
|
7773
8088
|
"One complete package: both runtimes, units and accounts are installed; --role only sets the initial enabled preset.",
|
|
7774
8089
|
"Hub and collector use separate unprivileged accounts; Node gets no capabilities.",
|
|
7775
8090
|
...options.enable && preset.hub ? ["Enabling the hub creates its owner account once and prints the password once."] : [],
|
|
@@ -7802,8 +8117,8 @@ async function installSystemUnlocked(options) {
|
|
|
7802
8117
|
`existing user service(s) detected (${detail}); stop them and use --adopt-user-state for explicit copy-based adoption`
|
|
7803
8118
|
);
|
|
7804
8119
|
}
|
|
7805
|
-
const source = (0,
|
|
7806
|
-
if (!(0,
|
|
8120
|
+
const source = (0, import_node_path19.resolve)(options.source);
|
|
8121
|
+
if (!(0, import_node_fs17.existsSync)(source)) throw new SystemError("missing-source", `release source does not exist: ${source}`);
|
|
7807
8122
|
const port = options.port ?? 8081;
|
|
7808
8123
|
if (!Number.isInteger(port) || port < 1 || port > 65535) throw new SystemError("invalid-argument", "--port must be 1-65535");
|
|
7809
8124
|
parseHubConfig(options.origin === void 0 ? { HUB_HOST: "127.0.0.1", HUB_PORT: String(port) } : { HUB_PUBLIC_ORIGIN: options.origin, HUB_SOCKET_PATH: hubSocketPath(paths) });
|
|
@@ -7824,14 +8139,14 @@ async function installSystemUnlocked(options) {
|
|
|
7824
8139
|
});
|
|
7825
8140
|
try {
|
|
7826
8141
|
if (legacy) resetUnfinishedSystemState({ paths, host, now });
|
|
7827
|
-
ensureDirectory((0,
|
|
8142
|
+
ensureDirectory((0, import_node_path19.join)(paths.prefix, "releases"), 493);
|
|
7828
8143
|
ensureDirectory(paths.stateDir, 493);
|
|
7829
8144
|
ensureDirectory(paths.configDir, 493);
|
|
7830
8145
|
ensureDirectory(paths.unitsDir, 493);
|
|
7831
|
-
ensureDirectory((0,
|
|
7832
|
-
ensureDirectory((0,
|
|
7833
|
-
ensureDirectory((0,
|
|
7834
|
-
ensureDirectory((0,
|
|
8146
|
+
ensureDirectory((0, import_node_path19.join)(paths.stateDir, "hub"), 448, true);
|
|
8147
|
+
ensureDirectory((0, import_node_path19.join)(paths.stateDir, "collector"), 448, true);
|
|
8148
|
+
ensureDirectory((0, import_node_path19.join)(paths.stateDir, "backups"), 448, true);
|
|
8149
|
+
ensureDirectory((0, import_node_path19.join)(paths.stateDir, "hub", "run"), 448, true);
|
|
7835
8150
|
const release = commitStagedRelease({ staged, paths, replaceRelease: options.replaceRelease });
|
|
7836
8151
|
let adoption = null;
|
|
7837
8152
|
if (options.adoptFrom) {
|
|
@@ -7864,13 +8179,13 @@ async function installSystemUnlocked(options) {
|
|
|
7864
8179
|
`, true);
|
|
7865
8180
|
writeUnitFile(paths, UNIT_NAMES.collector, `${collectorUnit}
|
|
7866
8181
|
`, true);
|
|
7867
|
-
const validation = runRequired(host, "systemd-analyze", ["verify", "--man=no", ...COMPONENTS3.map((component) => (0,
|
|
8182
|
+
const validation = runRequired(host, "systemd-analyze", ["verify", "--man=no", ...COMPONENTS3.map((component) => (0, import_node_path19.join)(paths.unitsDir, unitFor(component)))], "native systemd unit validation");
|
|
7868
8183
|
if (/path is not absolute|bad unit file|fatal error|unknown (?:key|lvalue)|ignoring/i.test(validation.stderr)) {
|
|
7869
8184
|
throw new SystemError("invalid-unit", "native systemd validation rejected a generated directive");
|
|
7870
8185
|
}
|
|
7871
8186
|
if (power) ensurePowerAccess(paths, accounts, host);
|
|
7872
|
-
chownAccount([(0,
|
|
7873
|
-
chownAccount([(0,
|
|
8187
|
+
chownAccount([(0, import_node_path19.join)(paths.stateDir, "hub")], accounts.hub, accounts.hub, host);
|
|
8188
|
+
chownAccount([(0, import_node_path19.join)(paths.stateDir, "collector")], accounts.collector, accounts.collector, host);
|
|
7874
8189
|
const state = emptyState({ paths, accounts, role, components: { hub: false, collector: false }, nodePath, now });
|
|
7875
8190
|
state.currentVersion = release.version;
|
|
7876
8191
|
state.releases[release.version] = {
|
|
@@ -7880,7 +8195,7 @@ async function installSystemUnlocked(options) {
|
|
|
7880
8195
|
};
|
|
7881
8196
|
state.adoption = adoption?.record ?? null;
|
|
7882
8197
|
state.power = power ? { enabled: true, rulePath: raplRulePath(paths), group: accounts.powerGroup } : null;
|
|
7883
|
-
replaceSymlink((0,
|
|
8198
|
+
replaceSymlink((0, import_node_path19.join)(paths.prefix, "current"), release.releaseDir, host);
|
|
7884
8199
|
writeSystemState(paths, state);
|
|
7885
8200
|
const wantsHub = preset.hub && (options.enable === true || options.start === true);
|
|
7886
8201
|
const wantsCollector = preset.collector && (options.enable === true || options.start === true);
|
|
@@ -7906,6 +8221,7 @@ async function installSystemUnlocked(options) {
|
|
|
7906
8221
|
await verifySystemHealth(paths, state, host, options.startupTimeoutMs ?? 2e4, started);
|
|
7907
8222
|
}
|
|
7908
8223
|
}
|
|
8224
|
+
recordMachineDataTransition(paths.stateDir, release.version, (path2, content) => atomicWrite(path2, content, 384));
|
|
7909
8225
|
return {
|
|
7910
8226
|
operation: "install",
|
|
7911
8227
|
ok: true,
|
|
@@ -7934,14 +8250,14 @@ function systemStatus(options = {}) {
|
|
|
7934
8250
|
} catch (error2) {
|
|
7935
8251
|
stateError = error2 instanceof Error ? error2.message : String(error2);
|
|
7936
8252
|
}
|
|
7937
|
-
const presentUnits = [UNIT_NAMES.hub, UNIT_NAMES.collector].filter((unit) => (0,
|
|
8253
|
+
const presentUnits = [UNIT_NAMES.hub, UNIT_NAMES.collector].filter((unit) => (0, import_node_fs17.existsSync)((0, import_node_path19.join)(paths.unitsDir, unit)));
|
|
7938
8254
|
const publicRole = presentUnits.length === 2 ? "local" : presentUnits[0] === UNIT_NAMES.hub ? "hub" : presentUnits[0] === UNIT_NAMES.collector ? "collector" : null;
|
|
7939
8255
|
const role = state?.role ?? publicRole ?? "local";
|
|
7940
8256
|
const current = currentReleaseDir(paths);
|
|
7941
8257
|
let publicVersion = null;
|
|
7942
8258
|
if (current) {
|
|
7943
8259
|
try {
|
|
7944
|
-
const manifest = JSON.parse((0,
|
|
8260
|
+
const manifest = JSON.parse((0, import_node_fs17.readFileSync)((0, import_node_path19.join)(current, "package.json"), "utf8"));
|
|
7945
8261
|
if (typeof manifest.version === "string") publicVersion = manifest.version;
|
|
7946
8262
|
} catch {
|
|
7947
8263
|
}
|
|
@@ -7952,7 +8268,7 @@ function systemStatus(options = {}) {
|
|
|
7952
8268
|
const componentReports = {};
|
|
7953
8269
|
for (const component of COMPONENTS3) {
|
|
7954
8270
|
const unit = unitFor(component);
|
|
7955
|
-
const present = (0,
|
|
8271
|
+
const present = (0, import_node_fs17.existsSync)((0, import_node_path19.join)(paths.unitsDir, unit));
|
|
7956
8272
|
const active = present && systemdActive(host, unit);
|
|
7957
8273
|
const unitEnabled2 = present && systemdEnabled(host, unit);
|
|
7958
8274
|
const enabled = state !== null ? state.components[component].enabled : unitEnabled2;
|
|
@@ -7961,7 +8277,7 @@ function systemStatus(options = {}) {
|
|
|
7961
8277
|
componentReports[component] = {
|
|
7962
8278
|
component,
|
|
7963
8279
|
unit,
|
|
7964
|
-
path: (0,
|
|
8280
|
+
path: (0, import_node_path19.join)(paths.unitsDir, unit),
|
|
7965
8281
|
present,
|
|
7966
8282
|
enabled,
|
|
7967
8283
|
unitEnabled: unitEnabled2,
|
|
@@ -8005,16 +8321,16 @@ function systemStatus(options = {}) {
|
|
|
8005
8321
|
})),
|
|
8006
8322
|
database: {
|
|
8007
8323
|
path: database,
|
|
8008
|
-
exists: (0,
|
|
8324
|
+
exists: (0, import_node_fs17.existsSync)(database),
|
|
8009
8325
|
schema,
|
|
8010
|
-
mode: (0,
|
|
8326
|
+
mode: (0, import_node_fs17.existsSync)(database) ? modeString((0, import_node_fs17.statSync)(database).mode) : null,
|
|
8011
8327
|
lock
|
|
8012
8328
|
},
|
|
8013
|
-
socket: { path: hubSocketPath(paths), exists: (0,
|
|
8329
|
+
socket: { path: hubSocketPath(paths), exists: (0, import_node_fs17.existsSync)(hubSocketPath(paths)) },
|
|
8014
8330
|
config: {
|
|
8015
8331
|
dir: paths.configDir,
|
|
8016
|
-
hubEnv: { path: hubEnvPath(paths), present: (0,
|
|
8017
|
-
collectorEnv: { path: collectorEnvPath(paths), present: (0,
|
|
8332
|
+
hubEnv: { path: hubEnvPath(paths), present: (0, import_node_fs17.existsSync)(hubEnvPath(paths)) },
|
|
8333
|
+
collectorEnv: { path: collectorEnvPath(paths), present: (0, import_node_fs17.existsSync)(collectorEnvPath(paths)) }
|
|
8018
8334
|
},
|
|
8019
8335
|
adoption: state?.adoption ?? null,
|
|
8020
8336
|
power,
|
|
@@ -8183,7 +8499,7 @@ async function enableSystem(options) {
|
|
|
8183
8499
|
],
|
|
8184
8500
|
files: [
|
|
8185
8501
|
{ path: component === "hub" ? hubEnvPath(paths) : collectorEnvPath(paths), mode: "0600", purpose: `${component} configuration` },
|
|
8186
|
-
{ path: (0,
|
|
8502
|
+
{ path: (0, import_node_path19.join)(paths.unitsDir, unitFor(component)), mode: "0644", purpose: `${component} boot unit` }
|
|
8187
8503
|
],
|
|
8188
8504
|
notes: [
|
|
8189
8505
|
"Enables only the requested component; the other component keeps running.",
|
|
@@ -8251,7 +8567,7 @@ function disableSystem(options) {
|
|
|
8251
8567
|
accounts: state.accounts,
|
|
8252
8568
|
commands: [`systemctl stop ${unitFor(component)}`, `systemctl disable ${unitFor(component)}`],
|
|
8253
8569
|
files: [],
|
|
8254
|
-
notes: ["Settings, credentials
|
|
8570
|
+
notes: ["Settings, credentials and stored history are retained while the component is disabled; unacknowledged samples held in the collector's RAM delivery queue drain with the process."]
|
|
8255
8571
|
};
|
|
8256
8572
|
if (options.apply !== true) return { operation: "disable", ok: true, apply: false, message: "plan only", plan };
|
|
8257
8573
|
assertApply(host);
|
|
@@ -8273,7 +8589,7 @@ function disableSystem(options) {
|
|
|
8273
8589
|
function readPrivateToken(path2, read) {
|
|
8274
8590
|
let stat;
|
|
8275
8591
|
try {
|
|
8276
|
-
stat = (0,
|
|
8592
|
+
stat = (0, import_node_fs17.lstatSync)(path2);
|
|
8277
8593
|
} catch (error2) {
|
|
8278
8594
|
if (error2.code === "ENOENT") {
|
|
8279
8595
|
throw new SystemError("missing-grant", `grant file does not exist: ${path2}`);
|
|
@@ -8284,7 +8600,7 @@ function readPrivateToken(path2, read) {
|
|
|
8284
8600
|
if ((stat.mode & 63) !== 0) throw new SystemError("insecure-permissions", `grant file must be private (0600): ${path2}`);
|
|
8285
8601
|
if (stat.size < 1 || stat.size > 4096) throw new SystemError("invalid-token", `grant file must contain 1-4096 bytes: ${path2}`);
|
|
8286
8602
|
if (!read) return void 0;
|
|
8287
|
-
const token = (0,
|
|
8603
|
+
const token = (0, import_node_fs17.readFileSync)(path2, "utf8").trim();
|
|
8288
8604
|
if (token === "" || /[\r\n\0]/.test(token) || !/^[\x21-\x7e]{1,256}$/.test(token)) {
|
|
8289
8605
|
throw new SystemError("invalid-token", "grant file contains an invalid token");
|
|
8290
8606
|
}
|
|
@@ -8296,7 +8612,7 @@ async function connectSystem(options) {
|
|
|
8296
8612
|
const state = readSystemState(paths);
|
|
8297
8613
|
if (state === null || !state.active) throw new SystemError("not-installed", "no active system installation; run install first");
|
|
8298
8614
|
const destination = connectDestinationUrl(options.url);
|
|
8299
|
-
const tokenFile = (0,
|
|
8615
|
+
const tokenFile = (0, import_node_path19.resolve)(options.tokenFile);
|
|
8300
8616
|
const configured = collectorConfigured(paths);
|
|
8301
8617
|
if (configured.configured) {
|
|
8302
8618
|
throw new SystemError(
|
|
@@ -8344,12 +8660,12 @@ async function connectSystem(options) {
|
|
|
8344
8660
|
`collector enrollment failed: ${error2 instanceof Error ? error2.message : String(error2)}`
|
|
8345
8661
|
);
|
|
8346
8662
|
} finally {
|
|
8347
|
-
chownAccount([(0,
|
|
8663
|
+
chownAccount([(0, import_node_path19.join)(paths.stateDir, "collector")], state.accounts.collector, state.accounts.collector, host);
|
|
8348
8664
|
}
|
|
8349
8665
|
if (!collectorConfigured(paths).configured) {
|
|
8350
8666
|
throw new SystemError("enrollment-failed", "the hub accepted enrollment but no destination was saved; check private state");
|
|
8351
8667
|
}
|
|
8352
|
-
chownAccount([(0,
|
|
8668
|
+
chownAccount([(0, import_node_path19.join)(paths.stateDir, "collector")], state.accounts.collector, state.accounts.collector, host);
|
|
8353
8669
|
writeSystemState(paths, state);
|
|
8354
8670
|
const enabled = state.components.collector.enabled;
|
|
8355
8671
|
if (enabled || wasActive) {
|
|
@@ -8366,13 +8682,16 @@ async function connectSystem(options) {
|
|
|
8366
8682
|
state
|
|
8367
8683
|
};
|
|
8368
8684
|
}
|
|
8685
|
+
function systemMachineDataPaths(paths) {
|
|
8686
|
+
return { database: hubDatabasePath(paths), queueTree: (0, import_node_path19.join)(paths.stateDir, "collector", "outbox") };
|
|
8687
|
+
}
|
|
8369
8688
|
async function upgradeSystemUnlocked(options) {
|
|
8370
8689
|
const host = options.host ?? createSystemHost();
|
|
8371
8690
|
const now = options.now ?? Date.now;
|
|
8372
8691
|
const paths = validateSystemPaths(options.paths);
|
|
8373
8692
|
if (systemStateIsLegacy(paths)) {
|
|
8374
|
-
const source2 = (0,
|
|
8375
|
-
if (!(0,
|
|
8693
|
+
const source2 = (0, import_node_path19.resolve)(options.source);
|
|
8694
|
+
if (!(0, import_node_fs17.existsSync)(source2)) throw new SystemError("missing-source", `release source does not exist: ${source2}`);
|
|
8376
8695
|
const role = legacySystemRole(paths);
|
|
8377
8696
|
const preset = componentsForRole(role);
|
|
8378
8697
|
const enable = options.enable ?? (options.start === true || unitNamesForComponents(preset).some((unit) => systemdEnabled(host, unit)));
|
|
@@ -8395,7 +8714,7 @@ async function upgradeSystemUnlocked(options) {
|
|
|
8395
8714
|
],
|
|
8396
8715
|
files: [
|
|
8397
8716
|
{ path: stateFilePath(paths), mode: "0600", purpose: "canonical replacement state" },
|
|
8398
|
-
{ path: (0,
|
|
8717
|
+
{ path: (0, import_node_path19.join)(paths.stateDir, "backups"), mode: "0700", purpose: "removed with unfinished history" }
|
|
8399
8718
|
],
|
|
8400
8719
|
notes: [
|
|
8401
8720
|
"An unfinished installation is reset, not migrated; its history and credentials are removed.",
|
|
@@ -8428,6 +8747,7 @@ async function upgradeSystemUnlocked(options) {
|
|
|
8428
8747
|
if (state === null || !state.active) throw new SystemError("not-installed", "no active system installation; run install first");
|
|
8429
8748
|
const activeComponents = COMPONENTS3.filter((component) => systemdActive(host, unitFor(component)));
|
|
8430
8749
|
const activeUnits = activeComponents.map(unitFor);
|
|
8750
|
+
const transitionPending = readMachineDataTransition(paths.stateDir) === null;
|
|
8431
8751
|
const plan = {
|
|
8432
8752
|
operation: "upgrade",
|
|
8433
8753
|
apply: options.apply === true,
|
|
@@ -8435,19 +8755,34 @@ async function upgradeSystemUnlocked(options) {
|
|
|
8435
8755
|
components: { hub: state.components.hub.enabled, collector: state.components.collector.enabled },
|
|
8436
8756
|
paths,
|
|
8437
8757
|
accounts: state.accounts,
|
|
8438
|
-
commands: [
|
|
8439
|
-
|
|
8758
|
+
commands: [
|
|
8759
|
+
"stage new release",
|
|
8760
|
+
...activeUnits.map((unit) => `systemctl stop ${unit}`),
|
|
8761
|
+
"backup database",
|
|
8762
|
+
...transitionPending ? ["discard legacy machine data and collector queues once (irreversible after success)"] : [],
|
|
8763
|
+
"switch current",
|
|
8764
|
+
...activeUnits.map((unit) => `systemctl start ${unit}`)
|
|
8765
|
+
],
|
|
8766
|
+
files: [
|
|
8767
|
+
{ path: (0, import_node_path19.join)(paths.stateDir, "backups"), mode: "0700", purpose: "pre-upgrade database backup" },
|
|
8768
|
+
...transitionPending ? [{ path: (0, import_node_path19.join)(paths.stateDir, "machine-data-transition.json"), mode: "0600", purpose: "written once after the transition completes" }] : []
|
|
8769
|
+
],
|
|
8440
8770
|
notes: [
|
|
8441
8771
|
"Staging happens before any service is stopped.",
|
|
8442
8772
|
"The exact active component set is restored; --start does not start a component that was stopped.",
|
|
8443
|
-
"A failed post-upgrade start restores the previous release and matching database backup."
|
|
8773
|
+
"A failed post-upgrade start restores the previous release and matching database backup.",
|
|
8774
|
+
...transitionPending ? [
|
|
8775
|
+
"This upgrade completes the one-time RAM-first machine-data transition: telemetry rows, summaries, receipts, gaps, latest snapshots, inventory and machine-derived alert history are discarded, plus the pre-RAM-first durable collector queue. The transition's database copy restores the rows and the staged queue is renamed back if activation fails.",
|
|
8776
|
+
`The transition always keeps ${machineDataKeptNote()}.`,
|
|
8777
|
+
"Later upgrades keep the marker and preserve durable history and queues."
|
|
8778
|
+
] : ["The one-time machine-data transition already completed; durable history and collector queues are preserved."]
|
|
8444
8779
|
]
|
|
8445
8780
|
};
|
|
8446
8781
|
if (options.apply !== true) return { operation: "upgrade", ok: true, apply: false, message: "plan only", plan };
|
|
8447
8782
|
assertApply(host);
|
|
8448
8783
|
assertManagedPathSafety(paths, isDefaultSystemLayout(paths));
|
|
8449
|
-
const source = (0,
|
|
8450
|
-
if (!(0,
|
|
8784
|
+
const source = (0, import_node_path19.resolve)(options.source);
|
|
8785
|
+
if (!(0, import_node_fs17.existsSync)(source)) throw new SystemError("missing-source", `release source does not exist: ${source}`);
|
|
8451
8786
|
const staged = prepareStagedRelease({
|
|
8452
8787
|
source,
|
|
8453
8788
|
paths,
|
|
@@ -8466,21 +8801,22 @@ async function upgradeSystemUnlocked(options) {
|
|
|
8466
8801
|
let backupPath = null;
|
|
8467
8802
|
let beforeSchema = null;
|
|
8468
8803
|
let release = null;
|
|
8804
|
+
let machineData = null;
|
|
8469
8805
|
try {
|
|
8470
8806
|
stopUnits(host, activeUnits);
|
|
8471
8807
|
assertDirectoryStopped(paths.stateDir);
|
|
8472
8808
|
const lock = systemLockState(paths);
|
|
8473
8809
|
if (lock.live) throw new SystemError("duplicate-runtime", `hub did not stop cleanly; lock remains at ${lock.path}`);
|
|
8474
8810
|
const database = hubDatabasePath(paths);
|
|
8475
|
-
if ((0,
|
|
8476
|
-
ensureDirectory((0,
|
|
8811
|
+
if ((0, import_node_fs17.existsSync)(database)) {
|
|
8812
|
+
ensureDirectory((0, import_node_path19.join)(paths.stateDir, "backups"), 448, true);
|
|
8477
8813
|
beforeSchema = databaseSchema(database);
|
|
8478
|
-
backupPath = (0,
|
|
8814
|
+
backupPath = (0, import_node_path19.join)(paths.stateDir, "backups", `pre-upgrade-${staged.version}-${newestTimestamp()}.sqlite`);
|
|
8479
8815
|
await backupDatabase2(database, backupPath, host);
|
|
8480
8816
|
}
|
|
8481
8817
|
release = commitStagedRelease({ staged, paths, replaceRelease: options.replaceRelease });
|
|
8482
|
-
replaceSymlink((0,
|
|
8483
|
-
replaceSymlink((0,
|
|
8818
|
+
replaceSymlink((0, import_node_path19.join)(paths.prefix, "previous"), oldCurrent, host);
|
|
8819
|
+
replaceSymlink((0, import_node_path19.join)(paths.prefix, "current"), release.releaseDir, host);
|
|
8484
8820
|
state.previousVersion = state.currentVersion;
|
|
8485
8821
|
state.currentVersion = release.version;
|
|
8486
8822
|
state.releases[release.version] = {
|
|
@@ -8489,7 +8825,7 @@ async function upgradeSystemUnlocked(options) {
|
|
|
8489
8825
|
installedAt: new Date(now()).toISOString()
|
|
8490
8826
|
};
|
|
8491
8827
|
if (backupPath !== null) {
|
|
8492
|
-
state.backups[(0,
|
|
8828
|
+
state.backups[(0, import_node_path19.basename)(backupPath)] = {
|
|
8493
8829
|
path: backupPath,
|
|
8494
8830
|
schemaVersion: beforeSchema,
|
|
8495
8831
|
fromSchema: beforeSchema,
|
|
@@ -8500,6 +8836,7 @@ async function upgradeSystemUnlocked(options) {
|
|
|
8500
8836
|
};
|
|
8501
8837
|
}
|
|
8502
8838
|
writeSystemState(paths, state);
|
|
8839
|
+
machineData = performMachineDataCleanup(paths.stateDir, systemMachineDataPaths(paths), now);
|
|
8503
8840
|
if (activeComponents.length > 0) {
|
|
8504
8841
|
startUnits(host, activeUnits);
|
|
8505
8842
|
await verifySystemHealth(paths, state, host, options.startupTimeoutMs ?? 2e4, activeComponents);
|
|
@@ -8512,6 +8849,7 @@ async function upgradeSystemUnlocked(options) {
|
|
|
8512
8849
|
oldPrevious,
|
|
8513
8850
|
beforeSchema,
|
|
8514
8851
|
backupPath,
|
|
8852
|
+
machineData,
|
|
8515
8853
|
host,
|
|
8516
8854
|
activeComponents,
|
|
8517
8855
|
units: activeUnits
|
|
@@ -8519,6 +8857,10 @@ async function upgradeSystemUnlocked(options) {
|
|
|
8519
8857
|
throw error2;
|
|
8520
8858
|
}
|
|
8521
8859
|
const upgraded = release;
|
|
8860
|
+
if (machineData !== null) {
|
|
8861
|
+
completeMachineDataCleanup(paths.stateDir, machineData, upgraded.version, (path2, content) => atomicWrite(path2, content, 384));
|
|
8862
|
+
}
|
|
8863
|
+
const machineHistory = machineData?.report;
|
|
8522
8864
|
return {
|
|
8523
8865
|
operation: "upgrade",
|
|
8524
8866
|
ok: true,
|
|
@@ -8528,6 +8870,7 @@ async function upgradeSystemUnlocked(options) {
|
|
|
8528
8870
|
current: upgraded.releaseDir,
|
|
8529
8871
|
previous: oldCurrent,
|
|
8530
8872
|
backupPath,
|
|
8873
|
+
...machineHistory ? { machineHistory } : {},
|
|
8531
8874
|
state
|
|
8532
8875
|
};
|
|
8533
8876
|
} finally {
|
|
@@ -8535,7 +8878,7 @@ async function upgradeSystemUnlocked(options) {
|
|
|
8535
8878
|
}
|
|
8536
8879
|
}
|
|
8537
8880
|
function systemOperationLockPath(paths) {
|
|
8538
|
-
return (0,
|
|
8881
|
+
return (0, import_node_path19.join)(paths.prefix, "run", "operation.lock");
|
|
8539
8882
|
}
|
|
8540
8883
|
async function withSystemOperation(options, operation) {
|
|
8541
8884
|
if (!options.apply) return operation();
|
|
@@ -8543,7 +8886,7 @@ async function withSystemOperation(options, operation) {
|
|
|
8543
8886
|
assertApply(host);
|
|
8544
8887
|
const paths = validateSystemPaths(options.paths);
|
|
8545
8888
|
ensureDirectory(paths.prefix, 493);
|
|
8546
|
-
ensureDirectory((0,
|
|
8889
|
+
ensureDirectory((0, import_node_path19.join)(paths.prefix, "run"), 448, true);
|
|
8547
8890
|
const release = acquireProcessLease(systemOperationLockPath(paths));
|
|
8548
8891
|
try {
|
|
8549
8892
|
return await operation();
|
|
@@ -8595,24 +8938,24 @@ async function rollbackSystemUnlocked(options = {}) {
|
|
|
8595
8938
|
try {
|
|
8596
8939
|
stopUnits(host, units);
|
|
8597
8940
|
assertDirectoryStopped(paths.stateDir);
|
|
8598
|
-
if (systemLockState(paths).live || lockIsLive((0,
|
|
8941
|
+
if (systemLockState(paths).live || lockIsLive((0, import_node_path19.join)(paths.stateDir, "collector/collector-runtime.lock")).live) {
|
|
8599
8942
|
throw new SystemError("runtime-active", "runtime lease remains after stop; rollback refused");
|
|
8600
8943
|
}
|
|
8601
8944
|
const database = hubDatabasePath(paths);
|
|
8602
|
-
const currentSchema = (0,
|
|
8945
|
+
const currentSchema = (0, import_node_fs17.existsSync)(database) ? databaseSchema(database) : null;
|
|
8603
8946
|
let backupToRestore = null;
|
|
8604
8947
|
if (currentSchema !== null && (previousSchema === null || currentSchema > previousSchema)) {
|
|
8605
8948
|
backupToRestore = pickRollbackBackup(state, previousSchema);
|
|
8606
|
-
if (backupToRestore === null || !(0,
|
|
8949
|
+
if (backupToRestore === null || !(0, import_node_fs17.existsSync)(backupToRestore.path)) {
|
|
8607
8950
|
throw new SystemError(
|
|
8608
8951
|
"incompatible-schema",
|
|
8609
8952
|
`current database schema ${currentSchema} is newer than release ${previousVersion}; no matching pre-upgrade backup is recorded`
|
|
8610
8953
|
);
|
|
8611
8954
|
}
|
|
8612
8955
|
}
|
|
8613
|
-
if ((0,
|
|
8614
|
-
ensureDirectory((0,
|
|
8615
|
-
safetyBackup = (0,
|
|
8956
|
+
if ((0, import_node_fs17.existsSync)(database)) {
|
|
8957
|
+
ensureDirectory((0, import_node_path19.join)(paths.stateDir, "backups"), 448, true);
|
|
8958
|
+
safetyBackup = (0, import_node_path19.join)(paths.stateDir, "backups", `pre-rollback-${newestTimestamp()}.sqlite`);
|
|
8616
8959
|
await backupDatabase2(database, safetyBackup, host);
|
|
8617
8960
|
}
|
|
8618
8961
|
if (backupToRestore !== null) {
|
|
@@ -8620,8 +8963,8 @@ async function rollbackSystemUnlocked(options = {}) {
|
|
|
8620
8963
|
restoredDatabase = true;
|
|
8621
8964
|
runRequired(host, "chown", [`${state.accounts.hub}:${state.accounts.hub}`, database], "restored database ownership");
|
|
8622
8965
|
}
|
|
8623
|
-
replaceSymlink((0,
|
|
8624
|
-
replaceSymlink((0,
|
|
8966
|
+
replaceSymlink((0, import_node_path19.join)(paths.prefix, "previous"), oldCurrent, host);
|
|
8967
|
+
replaceSymlink((0, import_node_path19.join)(paths.prefix, "current"), previous, host);
|
|
8625
8968
|
state.previousVersion = state.currentVersion;
|
|
8626
8969
|
state.currentVersion = previousVersion;
|
|
8627
8970
|
state.updatedAt = new Date(now()).toISOString();
|
|
@@ -8643,10 +8986,10 @@ async function rollbackSystemUnlocked(options = {}) {
|
|
|
8643
8986
|
};
|
|
8644
8987
|
} catch (error2) {
|
|
8645
8988
|
stopUnits(host, units);
|
|
8646
|
-
replaceSymlink((0,
|
|
8647
|
-
replaceSymlink((0,
|
|
8989
|
+
replaceSymlink((0, import_node_path19.join)(paths.prefix, "current"), oldCurrent, host);
|
|
8990
|
+
replaceSymlink((0, import_node_path19.join)(paths.prefix, "previous"), previous, host);
|
|
8648
8991
|
if (restoredDatabase && safetyBackup) {
|
|
8649
|
-
const failed = (0,
|
|
8992
|
+
const failed = (0, import_node_path19.join)(paths.stateDir, "backups", `failed-rollback-${newestTimestamp()}.sqlite`);
|
|
8650
8993
|
await backupDatabase2(hubDatabasePath(paths), failed, host);
|
|
8651
8994
|
replaceDatabaseFromBackup(safetyBackup, hubDatabasePath(paths), null, host);
|
|
8652
8995
|
runRequired(host, "chown", [`${state.accounts.hub}:${state.accounts.hub}`, hubDatabasePath(paths)], "restored database ownership");
|
|
@@ -8703,31 +9046,31 @@ function uninstallSystem(options = {}) {
|
|
|
8703
9046
|
assertDirectoryStopped(paths.stateDir);
|
|
8704
9047
|
for (const unit of units) runMaybe(host, "systemctl", ["disable", unit]);
|
|
8705
9048
|
for (const unit of units) {
|
|
8706
|
-
const path2 = (0,
|
|
9049
|
+
const path2 = (0, import_node_path19.join)(paths.unitsDir, unit);
|
|
8707
9050
|
assertManagedFileOwnership(paths, path2);
|
|
8708
9051
|
try {
|
|
8709
|
-
(0,
|
|
9052
|
+
(0, import_node_fs17.unlinkSync)(path2);
|
|
8710
9053
|
} catch {
|
|
8711
9054
|
}
|
|
8712
9055
|
}
|
|
8713
9056
|
runMaybe(host, "systemctl", ["daemon-reload"]);
|
|
8714
|
-
const hadPowerAccess = state?.power?.enabled === true || (0,
|
|
9057
|
+
const hadPowerAccess = state?.power?.enabled === true || (0, import_node_fs17.existsSync)(raplRulePath(paths)) || (0, import_node_fs17.existsSync)(powerOriginalPath(paths));
|
|
8715
9058
|
if (hadPowerAccess) {
|
|
8716
9059
|
try {
|
|
8717
|
-
(0,
|
|
9060
|
+
(0, import_node_fs17.unlinkSync)(raplRulePath(paths));
|
|
8718
9061
|
} catch {
|
|
8719
9062
|
}
|
|
8720
9063
|
try {
|
|
8721
|
-
(0,
|
|
9064
|
+
(0, import_node_fs17.unlinkSync)(powerSysusersPath(paths));
|
|
8722
9065
|
} catch {
|
|
8723
9066
|
}
|
|
8724
9067
|
restorePowerOriginals(paths, host);
|
|
8725
9068
|
resumePowerRule(paths, host);
|
|
8726
9069
|
}
|
|
8727
|
-
removeSymlink((0,
|
|
8728
|
-
removeSymlink((0,
|
|
8729
|
-
(0,
|
|
8730
|
-
if (options.preserveNode !== true) (0,
|
|
9070
|
+
removeSymlink((0, import_node_path19.join)(paths.prefix, "current"));
|
|
9071
|
+
removeSymlink((0, import_node_path19.join)(paths.prefix, "previous"));
|
|
9072
|
+
(0, import_node_fs17.rmSync)((0, import_node_path19.join)(paths.prefix, "releases"), { recursive: true, force: true });
|
|
9073
|
+
if (options.preserveNode !== true) (0, import_node_fs17.rmSync)((0, import_node_path19.join)(paths.prefix, "node"), { recursive: true, force: true });
|
|
8731
9074
|
if (state !== null) {
|
|
8732
9075
|
state.active = false;
|
|
8733
9076
|
state.power = null;
|
|
@@ -8740,8 +9083,8 @@ function uninstallSystem(options = {}) {
|
|
|
8740
9083
|
for (const group of [accounts.powerGroup, accounts.hub, accounts.collector]) runMaybe(host, "groupdel", [group]);
|
|
8741
9084
|
}
|
|
8742
9085
|
if (options.purgeData === true) {
|
|
8743
|
-
(0,
|
|
8744
|
-
(0,
|
|
9086
|
+
(0, import_node_fs17.rmSync)(paths.stateDir, { recursive: true, force: true });
|
|
9087
|
+
(0, import_node_fs17.rmSync)(paths.configDir, { recursive: true, force: true });
|
|
8745
9088
|
}
|
|
8746
9089
|
return {
|
|
8747
9090
|
operation: "uninstall",
|
|
@@ -8791,7 +9134,7 @@ function grantPower(options = {}) {
|
|
|
8791
9134
|
writeManagedFile(powerSysusersPath(paths), renderPowerSysusers(paths, accounts), 420, true);
|
|
8792
9135
|
runRequired(host, "systemd-sysusers", [], "power group creation");
|
|
8793
9136
|
assertSystemAccounts(host, accounts, true, ["collector"]);
|
|
8794
|
-
if (!(0,
|
|
9137
|
+
if (!(0, import_node_fs17.existsSync)(powerOriginalPath(paths))) capturePowerOriginals(paths);
|
|
8795
9138
|
writePowerRule(paths, accounts);
|
|
8796
9139
|
resumePowerRule(paths, host);
|
|
8797
9140
|
applyPowerAccess(paths, accounts, host);
|
|
@@ -8820,11 +9163,11 @@ function revokePower(options = {}) {
|
|
|
8820
9163
|
if (options.apply !== true) return { operation: "power-revoke", ok: true, apply: false, message: "plan only", plan };
|
|
8821
9164
|
assertApply(host);
|
|
8822
9165
|
try {
|
|
8823
|
-
(0,
|
|
9166
|
+
(0, import_node_fs17.unlinkSync)(raplRulePath(paths));
|
|
8824
9167
|
} catch {
|
|
8825
9168
|
}
|
|
8826
9169
|
try {
|
|
8827
|
-
(0,
|
|
9170
|
+
(0, import_node_fs17.unlinkSync)(powerSysusersPath(paths));
|
|
8828
9171
|
} catch {
|
|
8829
9172
|
}
|
|
8830
9173
|
restorePowerOriginals(paths, host);
|
|
@@ -9040,6 +9383,12 @@ function printMutationReport(report) {
|
|
|
9040
9383
|
console.log("then run `rigscope system connect https://<hub> --token-file <file> --apply`.");
|
|
9041
9384
|
}
|
|
9042
9385
|
}
|
|
9386
|
+
function printMachineDataOutcome(machineHistory) {
|
|
9387
|
+
if (machineHistory === void 0) return;
|
|
9388
|
+
const described = describeMachineDataReport(machineHistory);
|
|
9389
|
+
console.log(described.summary);
|
|
9390
|
+
if (described.warning) console.log(`Warning: ${described.warning}`);
|
|
9391
|
+
}
|
|
9043
9392
|
async function runSystemCommand(argv) {
|
|
9044
9393
|
const parsed = parseSystemArgs(argv);
|
|
9045
9394
|
if (parsed.command === "help") {
|
|
@@ -9111,7 +9460,7 @@ ${humanPlan(report.plan)}`);
|
|
|
9111
9460
|
if (parsed.command === "logs") {
|
|
9112
9461
|
const selected = validateSystemPaths(paths);
|
|
9113
9462
|
const component = componentFrom(parsed, false);
|
|
9114
|
-
const units = (component ? [unitFor(component)] : [UNIT_NAMES.hub, UNIT_NAMES.collector]).filter((unit) => (0,
|
|
9463
|
+
const units = (component ? [unitFor(component)] : [UNIT_NAMES.hub, UNIT_NAMES.collector]).filter((unit) => (0, import_node_fs17.existsSync)((0, import_node_path19.join)(selected.unitsDir, unit)));
|
|
9115
9464
|
if (units.length === 0) throw new SystemError("not-installed", component ? `${component} logs are unavailable; its unit is not installed` : "no system services installed");
|
|
9116
9465
|
const result = (0, import_node_child_process5.spawnSync)("journalctl", [...units.flatMap((unit) => ["--unit", unit]), "--lines=100", "--no-pager", ...boolValue(values, "follow") ? ["--follow"] : []], { stdio: "inherit" });
|
|
9117
9466
|
if (result.error) throw result.error;
|
|
@@ -9187,6 +9536,7 @@ ${humanPlan(report.plan)}`);
|
|
|
9187
9536
|
else {
|
|
9188
9537
|
printMutationReport(report);
|
|
9189
9538
|
console.log(`Backup: ${report.backupPath ?? "none"}`);
|
|
9539
|
+
printMachineDataOutcome(report.machineHistory);
|
|
9190
9540
|
}
|
|
9191
9541
|
return 0;
|
|
9192
9542
|
}
|
|
@@ -9292,7 +9642,7 @@ if (isMainModule()) {
|
|
|
9292
9642
|
}
|
|
9293
9643
|
|
|
9294
9644
|
// src/cli/selection.ts
|
|
9295
|
-
var
|
|
9645
|
+
var import_node_fs18 = require("node:fs");
|
|
9296
9646
|
function selectInstallation(options) {
|
|
9297
9647
|
if (options.scope !== void 0 && options.scope !== "user" && options.scope !== "system") {
|
|
9298
9648
|
throw new Error("--scope must be user or system.");
|
|
@@ -9308,16 +9658,16 @@ function selectInstallation(options) {
|
|
|
9308
9658
|
return options.systemPresent ? "system" : "user";
|
|
9309
9659
|
}
|
|
9310
9660
|
function systemInstallationPresent() {
|
|
9311
|
-
return (0,
|
|
9661
|
+
return (0, import_node_fs18.existsSync)("/opt/rigscope/current") || (0, import_node_fs18.existsSync)("/etc/systemd/system/rigscope-hub.service") || (0, import_node_fs18.existsSync)("/etc/systemd/system/rigscope-collector.service");
|
|
9312
9662
|
}
|
|
9313
9663
|
|
|
9314
9664
|
// src/cli/access.ts
|
|
9315
|
-
var
|
|
9316
|
-
var
|
|
9317
|
-
var
|
|
9665
|
+
var import_node_fs19 = require("node:fs");
|
|
9666
|
+
var import_node_path20 = require("node:path");
|
|
9667
|
+
var import_node_crypto14 = require("node:crypto");
|
|
9318
9668
|
|
|
9319
9669
|
// collector/destinations/outbox.ts
|
|
9320
|
-
var
|
|
9670
|
+
var import_node_crypto13 = require("node:crypto");
|
|
9321
9671
|
var path = __toESM(require("node:path"));
|
|
9322
9672
|
var import_node_sqlite5 = require("node:sqlite");
|
|
9323
9673
|
var DEFAULT_OUTBOX_LIMITS = {
|
|
@@ -9329,7 +9679,7 @@ var DEFAULT_OUTBOX_LIMITS = {
|
|
|
9329
9679
|
var DEFAULT_OUTBOX_DISK_BYTES = 80 * 1024 * 1024;
|
|
9330
9680
|
var WRITE_HEADROOM_BYTES = 16 * 1024;
|
|
9331
9681
|
function outboxDirFor(stateDir, url) {
|
|
9332
|
-
const digest = (0,
|
|
9682
|
+
const digest = (0, import_node_crypto13.createHash)("sha256").update(url, "utf8").digest("hex").slice(0, 16);
|
|
9333
9683
|
return path.join(stateDir, "outbox", digest);
|
|
9334
9684
|
}
|
|
9335
9685
|
|
|
@@ -9339,7 +9689,7 @@ function endpointFor(config) {
|
|
|
9339
9689
|
}
|
|
9340
9690
|
function readCollectorState(dir) {
|
|
9341
9691
|
try {
|
|
9342
|
-
return JSON.parse(readPrivate((0,
|
|
9692
|
+
return JSON.parse(readPrivate((0, import_node_path20.join)(dir, "collector", "state.json")));
|
|
9343
9693
|
} catch (error2) {
|
|
9344
9694
|
if (error2.code === "ENOENT") return null;
|
|
9345
9695
|
throw error2;
|
|
@@ -9364,7 +9714,7 @@ function planAccessChange(dir, options) {
|
|
|
9364
9714
|
delete next.socket;
|
|
9365
9715
|
} else if (options.origin) {
|
|
9366
9716
|
next.origin = options.origin;
|
|
9367
|
-
next.socket = options.socket ?? (0,
|
|
9717
|
+
next.socket = options.socket ?? (0, import_node_path20.join)(dir, "run", "hub.sock");
|
|
9368
9718
|
}
|
|
9369
9719
|
parseHubConfig(hubEnvironment(dir, next));
|
|
9370
9720
|
const oldEndpoint = endpointFor(previous);
|
|
@@ -9380,8 +9730,8 @@ function planAccessChange(dir, options) {
|
|
|
9380
9730
|
collectorChanged,
|
|
9381
9731
|
oldEndpoint,
|
|
9382
9732
|
newEndpoint,
|
|
9383
|
-
oldQueue: collectorChanged ? outboxDirFor((0,
|
|
9384
|
-
newQueue: collectorChanged ? outboxDirFor((0,
|
|
9733
|
+
oldQueue: collectorChanged ? outboxDirFor((0, import_node_path20.join)(dir, "collector"), oldEndpoint) : null,
|
|
9734
|
+
newQueue: collectorChanged ? outboxDirFor((0, import_node_path20.join)(dir, "collector"), newEndpoint) : null,
|
|
9385
9735
|
state,
|
|
9386
9736
|
self
|
|
9387
9737
|
};
|
|
@@ -9389,22 +9739,22 @@ function planAccessChange(dir, options) {
|
|
|
9389
9739
|
function configureAccess(dir, options) {
|
|
9390
9740
|
const plan = planAccessChange(dir, options);
|
|
9391
9741
|
if (!plan.changed) return { changed: false, backup: null, url: plan.url };
|
|
9392
|
-
const configPath = (0,
|
|
9393
|
-
const statePath = (0,
|
|
9742
|
+
const configPath = (0, import_node_path20.join)(dir, "config.json");
|
|
9743
|
+
const statePath = (0, import_node_path20.join)(dir, "collector", "state.json");
|
|
9394
9744
|
const beforeConfig = readPrivate(configPath);
|
|
9395
9745
|
const beforeState = plan.state === null ? null : readPrivate(statePath);
|
|
9396
|
-
if (plan.collectorChanged && plan.oldQueue && plan.newQueue && plan.oldQueue !== plan.newQueue && (0,
|
|
9746
|
+
if (plan.collectorChanged && plan.oldQueue && plan.newQueue && plan.oldQueue !== plan.newQueue && (0, import_node_fs19.existsSync)(plan.newQueue)) {
|
|
9397
9747
|
throw new Error("The destination already has an outbox. Preserve or replay it before changing access.");
|
|
9398
9748
|
}
|
|
9399
|
-
if (plan.oldQueue && (0,
|
|
9400
|
-
const stat = (0,
|
|
9749
|
+
if (plan.oldQueue && (0, import_node_fs19.existsSync)(plan.oldQueue)) {
|
|
9750
|
+
const stat = (0, import_node_fs19.lstatSync)(plan.oldQueue);
|
|
9401
9751
|
if (!stat.isDirectory() || stat.isSymbolicLink()) throw new Error("Collector outbox must be a real directory.");
|
|
9402
9752
|
}
|
|
9403
|
-
const backup3 = (0,
|
|
9753
|
+
const backup3 = (0, import_node_path20.join)(dir, "backups", `access-${(0, import_node_crypto14.randomUUID)()}`);
|
|
9404
9754
|
privateDirectory(backup3);
|
|
9405
|
-
writePrivateFile((0,
|
|
9406
|
-
if (beforeState !== null) writePrivateFile((0,
|
|
9407
|
-
writePrivateFile((0,
|
|
9755
|
+
writePrivateFile((0, import_node_path20.join)(backup3, "config.json"), beforeConfig);
|
|
9756
|
+
if (beforeState !== null) writePrivateFile((0, import_node_path20.join)(backup3, "collector-state.json"), beforeState);
|
|
9757
|
+
writePrivateFile((0, import_node_path20.join)(backup3, "change.json"), JSON.stringify({
|
|
9408
9758
|
oldEndpoint: plan.collectorChanged ? plan.oldEndpoint : null,
|
|
9409
9759
|
newEndpoint: plan.collectorChanged ? plan.newEndpoint : null,
|
|
9410
9760
|
oldQueue: plan.oldQueue,
|
|
@@ -9412,8 +9762,8 @@ function configureAccess(dir, options) {
|
|
|
9412
9762
|
}));
|
|
9413
9763
|
let movedQueue = false;
|
|
9414
9764
|
try {
|
|
9415
|
-
if (plan.oldQueue && plan.newQueue && plan.oldQueue !== plan.newQueue && (0,
|
|
9416
|
-
(0,
|
|
9765
|
+
if (plan.oldQueue && plan.newQueue && plan.oldQueue !== plan.newQueue && (0, import_node_fs19.existsSync)(plan.oldQueue)) {
|
|
9766
|
+
(0, import_node_fs19.renameSync)(plan.oldQueue, plan.newQueue);
|
|
9417
9767
|
movedQueue = true;
|
|
9418
9768
|
}
|
|
9419
9769
|
if (plan.collectorChanged && plan.state && plan.self) {
|
|
@@ -9429,7 +9779,7 @@ function configureAccess(dir, options) {
|
|
|
9429
9779
|
try {
|
|
9430
9780
|
writePrivateFile(configPath, beforeConfig);
|
|
9431
9781
|
if (beforeState !== null) writePrivateFile(statePath, beforeState);
|
|
9432
|
-
if (movedQueue) (0,
|
|
9782
|
+
if (movedQueue) (0, import_node_fs19.renameSync)(plan.newQueue, plan.oldQueue);
|
|
9433
9783
|
} catch {
|
|
9434
9784
|
throw new Error(`Access change could not be recovered. Keep the service stopped and restore configuration from ${backup3}.`);
|
|
9435
9785
|
}
|
|
@@ -9439,7 +9789,7 @@ function configureAccess(dir, options) {
|
|
|
9439
9789
|
}
|
|
9440
9790
|
|
|
9441
9791
|
// src/cli/main.ts
|
|
9442
|
-
var ROOT = (0,
|
|
9792
|
+
var ROOT = (0, import_node_path21.resolve)(__dirname, "..");
|
|
9443
9793
|
var HELP2 = `Rigscope \u2014 your machines, in view
|
|
9444
9794
|
|
|
9445
9795
|
Usage: rigscope <command> [options]
|
|
@@ -9560,7 +9910,7 @@ async function readPassword() {
|
|
|
9560
9910
|
}
|
|
9561
9911
|
}
|
|
9562
9912
|
function passwordFromFile(path2) {
|
|
9563
|
-
const raw = readPrivate((0,
|
|
9913
|
+
const raw = readPrivate((0, import_node_path21.resolve)(path2));
|
|
9564
9914
|
return raw.replace(/\r?\n$/, "");
|
|
9565
9915
|
}
|
|
9566
9916
|
function healthDeadline(value) {
|
|
@@ -9601,7 +9951,12 @@ function announce(setup, dir) {
|
|
|
9601
9951
|
Password: ${setup.password}`);
|
|
9602
9952
|
printWarning("Save this password; it is shown once.");
|
|
9603
9953
|
}
|
|
9604
|
-
console.log(`Configuration: ${(0,
|
|
9954
|
+
console.log(`Configuration: ${(0, import_node_path21.join)(dir, "config.json")}`);
|
|
9955
|
+
}
|
|
9956
|
+
function printMachineDataOutcome2(machineHistory) {
|
|
9957
|
+
const described = describeMachineDataReport(machineHistory);
|
|
9958
|
+
console.log(described.summary);
|
|
9959
|
+
if (described.warning !== null) printWarning(described.warning);
|
|
9605
9960
|
}
|
|
9606
9961
|
async function main() {
|
|
9607
9962
|
const argv = process.argv.slice(2);
|
|
@@ -9641,7 +9996,7 @@ async function main() {
|
|
|
9641
9996
|
return 0;
|
|
9642
9997
|
}
|
|
9643
9998
|
if (values.version) {
|
|
9644
|
-
console.log(JSON.parse((0,
|
|
9999
|
+
console.log(JSON.parse((0, import_node_fs20.readFileSync)((0, import_node_path21.join)(ROOT, "package.json"), "utf8")).version);
|
|
9645
10000
|
return 0;
|
|
9646
10001
|
}
|
|
9647
10002
|
if (process.platform !== "linux") throw new Error("Rigscope currently supports Linux.");
|
|
@@ -9673,13 +10028,13 @@ async function main() {
|
|
|
9673
10028
|
if (value !== void 0 && key !== "state-dir" && key !== "scope" && !(permitted[command] ?? []).includes(key)) throw new Error(`--${key} is not available for ${command}.`);
|
|
9674
10029
|
}
|
|
9675
10030
|
if (values.origin?.endsWith("/")) values.origin = values.origin.slice(0, -1);
|
|
9676
|
-
const managedState = (0,
|
|
10031
|
+
const managedState = (0, import_node_path21.basename)(ROOT) === "rigscope" && (0, import_node_path21.basename)((0, import_node_path21.dirname)(ROOT)) === "node_modules" && (0, import_node_path21.basename)((0, import_node_path21.resolve)(ROOT, "../..")) === "runtime" ? (0, import_node_path21.resolve)(ROOT, "../../..") : void 0;
|
|
9677
10032
|
const dir = stateDirectory(values["state-dir"] ?? (command === "try" ? `${stateDirectory()}-trial` : process.env.RIGSCOPE_STATE_DIR ?? managedState));
|
|
9678
10033
|
const explicitState = Boolean(values["state-dir"] || process.env.RIGSCOPE_STATE_DIR || managedState || command === "try" || command === "run");
|
|
9679
10034
|
const scope = selectInstallation({
|
|
9680
10035
|
scope: values.scope ?? (explicitState ? "user" : void 0),
|
|
9681
10036
|
explicitState: Boolean(values["state-dir"]),
|
|
9682
|
-
userPresent: (0,
|
|
10037
|
+
userPresent: (0, import_node_fs20.existsSync)((0, import_node_path21.join)(dir, "config.json")),
|
|
9683
10038
|
systemPresent: systemInstallationPresent()
|
|
9684
10039
|
});
|
|
9685
10040
|
if (scope === "system") {
|
|
@@ -9689,7 +10044,7 @@ async function main() {
|
|
|
9689
10044
|
throw new Error(`System installation selected. Use rigscope system ${command} (mutations require sudo and --apply), or --scope user for a user installation.`);
|
|
9690
10045
|
}
|
|
9691
10046
|
if (command === "config") {
|
|
9692
|
-
console.log((0,
|
|
10047
|
+
console.log((0, import_node_path21.join)(dir, "config.json"));
|
|
9693
10048
|
return 0;
|
|
9694
10049
|
}
|
|
9695
10050
|
if (command === "upgrade" && installationNeedsReset(dir)) {
|
|
@@ -9720,7 +10075,7 @@ async function main() {
|
|
|
9720
10075
|
if (values.enable && values["no-enable"]) throw new Error("Choose --enable or --no-enable.");
|
|
9721
10076
|
if (values.boot && values["no-enable"]) throw new Error("--boot requires startup to be enabled.");
|
|
9722
10077
|
}
|
|
9723
|
-
const grant = command === "connect" ? values["token-file"] ? readPrivate((0,
|
|
10078
|
+
const grant = command === "connect" ? values["token-file"] ? readPrivate((0, import_node_path21.resolve)(values["token-file"])).trim() : await readGrant() : void 0;
|
|
9724
10079
|
let recoveryPassword;
|
|
9725
10080
|
if (command === "recover-password") {
|
|
9726
10081
|
const saved = readSetup(dir);
|
|
@@ -9758,7 +10113,7 @@ async function main() {
|
|
|
9758
10113
|
}
|
|
9759
10114
|
if (command === "try") {
|
|
9760
10115
|
if (values.role && values.role !== "local") throw new Error("Use install for a hub or collector.");
|
|
9761
|
-
if ((0,
|
|
10116
|
+
if ((0, import_node_fs20.existsSync)((0, import_node_path21.join)(dir, "runtime"))) throw new Error("This is an installed runtime. Use rigscope start, or choose a separate --state-dir for a trial.");
|
|
9762
10117
|
const setup = initialize(dir, { role: "local", port: values.port ?? "8082" });
|
|
9763
10118
|
console.log("Trial: foreground hub + collector. Ctrl+C stops both.");
|
|
9764
10119
|
announce(setup, dir);
|
|
@@ -9774,20 +10129,20 @@ async function main() {
|
|
|
9774
10129
|
const releases = [];
|
|
9775
10130
|
try {
|
|
9776
10131
|
releases.push(acquireProcessLease(componentLeasePath(dir, "collector")));
|
|
9777
|
-
releases.push(acquireProcessLease((0,
|
|
9778
|
-
await enrollCollector((0,
|
|
10132
|
+
releases.push(acquireProcessLease((0, import_node_path21.join)(dir, "collector", "collector-runtime.lock")));
|
|
10133
|
+
await enrollCollector((0, import_node_path21.join)(dir, "collector", "state.json"), url, token, DEFAULT_SHARING, values.replace);
|
|
9779
10134
|
} finally {
|
|
9780
10135
|
for (const release of releases.reverse()) release();
|
|
9781
10136
|
}
|
|
9782
10137
|
configureComponent(dir, "collector", { enabled: true, pairColocated: false });
|
|
9783
|
-
if ((0,
|
|
10138
|
+
if ((0, import_node_fs20.existsSync)((0, import_node_path21.join)(dir, "runtime"))) {
|
|
9784
10139
|
writeService(dir, "collector");
|
|
9785
10140
|
systemctl(dir, "enable", false, "collector");
|
|
9786
10141
|
}
|
|
9787
|
-
if (!values["no-start"] && !values["no-restart"] && (0,
|
|
10142
|
+
if (!values["no-start"] && !values["no-restart"] && (0, import_node_fs20.existsSync)(unitPath(dir, "collector"))) {
|
|
9788
10143
|
console.log(`Hub connected. Background service ${await startInstallation(dir, "collector")}.`);
|
|
9789
10144
|
} else {
|
|
9790
|
-
console.log(`Hub connected. Run rigscope ${(0,
|
|
10145
|
+
console.log(`Hub connected. Run rigscope ${(0, import_node_fs20.existsSync)(unitPath(dir, "collector")) ? "start collector" : `install --state-dir ${shellQuote2(dir)}`}.`);
|
|
9791
10146
|
}
|
|
9792
10147
|
return 0;
|
|
9793
10148
|
}
|
|
@@ -9796,10 +10151,10 @@ async function main() {
|
|
|
9796
10151
|
const existing = readSetup(dir);
|
|
9797
10152
|
if (!existing) throw new Error("No saved installation. Run rigscope install first.");
|
|
9798
10153
|
if (command === "enable") {
|
|
9799
|
-
if (!(0,
|
|
10154
|
+
if (!(0, import_node_fs20.existsSync)((0, import_node_path21.join)(dir, "runtime"))) throw new Error("Install the runtime first: rigscope install --no-start.");
|
|
9800
10155
|
if (target === "hub" && (existing.users.length > 0 || existing.origin) && (values.origin !== void 0 || values.socket !== void 0 || values.port !== void 0)) {
|
|
9801
10156
|
const nextOrigin = values.origin !== void 0 ? values.origin : existing.origin;
|
|
9802
|
-
const nextSocket = values.origin !== void 0 ? values.socket ?? (0,
|
|
10157
|
+
const nextSocket = values.origin !== void 0 ? values.socket ?? (0, import_node_path21.join)(dir, "run", "hub.sock") : values.socket ?? existing.socket;
|
|
9803
10158
|
const nextPort = values.port !== void 0 ? Number(values.port) : existing.port;
|
|
9804
10159
|
if (nextOrigin !== existing.origin || nextSocket !== existing.socket || nextPort !== existing.port) {
|
|
9805
10160
|
throw new Error("Change hub access with rigscope configure.");
|
|
@@ -9837,7 +10192,7 @@ Save this password; it is shown once.`);
|
|
|
9837
10192
|
if (values.boot && values["no-enable"]) throw new Error("--boot requires startup to be enabled.");
|
|
9838
10193
|
const resetting = installationNeedsReset(dir);
|
|
9839
10194
|
if (resetting) values.role = values.role ?? installationRole(dir);
|
|
9840
|
-
const release = resetting || serviceActive(dir) && (0,
|
|
10195
|
+
const release = resetting || serviceActive(dir) && (0, import_node_fs20.existsSync)((0, import_node_path21.join)(dir, "runtime")) ? () => {
|
|
9841
10196
|
} : acquireProcessLease(combinedLeasePath(dir));
|
|
9842
10197
|
let alias;
|
|
9843
10198
|
let installedVersion;
|
|
@@ -9845,7 +10200,7 @@ Save this password; it is shown once.`);
|
|
|
9845
10200
|
if (resetting) {
|
|
9846
10201
|
console.log("Old installation state detected. Resetting configuration and history, then installing the replacement\u2026");
|
|
9847
10202
|
validateSetupOptions({ role: values.role, port: values.port, origin: values.origin, socket: values.socket });
|
|
9848
|
-
const source = values.from ? /^[./]/.test(values.from) ? (0,
|
|
10203
|
+
const source = values.from ? /^[./]/.test(values.from) ? (0, import_node_path21.resolve)(values.from) : values.from : void 0;
|
|
9849
10204
|
const stage = stagePackage(ROOT, dir, source);
|
|
9850
10205
|
let setup;
|
|
9851
10206
|
try {
|
|
@@ -9855,26 +10210,27 @@ Save this password; it is shown once.`);
|
|
|
9855
10210
|
setup: { role: values.role, port: values.port, origin: values.origin, socket: values.socket }
|
|
9856
10211
|
});
|
|
9857
10212
|
} catch (error2) {
|
|
9858
|
-
(0,
|
|
10213
|
+
(0, import_node_fs20.rmSync)(stage, { recursive: true, force: true });
|
|
9859
10214
|
throw error2;
|
|
9860
10215
|
}
|
|
9861
10216
|
announce(setup, dir);
|
|
9862
|
-
installedVersion = runtimeVersion((0,
|
|
10217
|
+
installedVersion = runtimeVersion((0, import_node_path21.join)(dir, "runtime"));
|
|
9863
10218
|
writeRuntimeState(dir, { ...readRuntimeState(dir) ?? emptyRuntimeState(dir), currentVersion: installedVersion });
|
|
9864
10219
|
} else {
|
|
9865
10220
|
const setup = initialize(dir, { role: values.role, port: values.port, origin: values.origin, socket: values.socket });
|
|
9866
10221
|
announce(setup, dir);
|
|
9867
|
-
if ((0,
|
|
10222
|
+
if ((0, import_node_fs20.existsSync)((0, import_node_path21.join)(dir, "runtime"))) {
|
|
9868
10223
|
if (values.from) throw new Error("Runtime already installed. Use rigscope upgrade --from <package>.");
|
|
9869
10224
|
} else {
|
|
9870
10225
|
console.log("Installing runtime\u2026");
|
|
9871
|
-
const source = values.from ? /^[./]/.test(values.from) ? (0,
|
|
10226
|
+
const source = values.from ? /^[./]/.test(values.from) ? (0, import_node_path21.resolve)(values.from) : values.from : void 0;
|
|
9872
10227
|
const stage = stagePackage(ROOT, dir, source);
|
|
9873
10228
|
activatePackage(dir, stage);
|
|
9874
10229
|
}
|
|
9875
|
-
installedVersion = runtimeVersion((0,
|
|
10230
|
+
installedVersion = runtimeVersion((0, import_node_path21.join)(dir, "runtime"));
|
|
9876
10231
|
writeRuntimeState(dir, { ...readRuntimeState(dir) ?? emptyRuntimeState(dir), currentVersion: installedVersion });
|
|
9877
10232
|
}
|
|
10233
|
+
recordMachineDataTransition(dir, installedVersion);
|
|
9878
10234
|
writeService(dir);
|
|
9879
10235
|
alias = installAlias(dir, ROOT);
|
|
9880
10236
|
const installedConfig = readSetup(dir);
|
|
@@ -9920,7 +10276,7 @@ Services: ${components2.map((target) => unitName(dir, target)).join(", ")}`);
|
|
|
9920
10276
|
}
|
|
9921
10277
|
const startup = startupStatus(dir);
|
|
9922
10278
|
console.log(`Startup: ${!startup.enabled ? "manual" : startup.linger ? "at boot; continues after logout" : "at login; use install --boot to continue after logout"}`);
|
|
9923
|
-
if (!(process.env.PATH ?? "").split(":").includes((0,
|
|
10279
|
+
if (!(process.env.PATH ?? "").split(":").includes((0, import_node_path21.resolve)(alias, ".."))) console.log(`Add ${(0, import_node_path21.resolve)(alias, "..")} to PATH, or use the command path above.`);
|
|
9924
10280
|
return 0;
|
|
9925
10281
|
}
|
|
9926
10282
|
if (command === "doctor") {
|
|
@@ -9936,7 +10292,7 @@ Services: ${components2.map((target) => unitName(dir, target)).join(", ")}`);
|
|
|
9936
10292
|
const config = readSetup(dir);
|
|
9937
10293
|
if (!config) {
|
|
9938
10294
|
if (command === "status") {
|
|
9939
|
-
console.log(`Rigscope ${JSON.parse((0,
|
|
10295
|
+
console.log(`Rigscope ${JSON.parse((0, import_node_fs20.readFileSync)((0, import_node_path21.join)(ROOT, "package.json"), "utf8")).version}
|
|
9940
10296
|
No user installation.
|
|
9941
10297
|
Install background monitoring: rigscope install --boot
|
|
9942
10298
|
Connect to a hub: rigscope install --role collector --boot
|
|
@@ -9957,25 +10313,25 @@ ${bold("Components")}:`);
|
|
|
9957
10313
|
console.log(` ${bold(label2(target))}: ${componentEnabled(config, target) ? "enabled" : "disabled"}, ${colorize(state2, service.active ? "green" : "gray")}, startup ${service.enabled ? "on" : "off"}${service.installed ? "" : " (not installed)"}`);
|
|
9958
10314
|
if (service.active && service.execMainPid) console.log(` PID ${service.execMainPid}`);
|
|
9959
10315
|
}
|
|
9960
|
-
console.log(`Configuration: ${(0,
|
|
10316
|
+
console.log(`Configuration: ${(0, import_node_path21.join)(dir, "config.json")}
|
|
9961
10317
|
Startup: ${!startup.enabled ? "manual" : startup.linger ? "at boot; continues after logout" : "at login only"}
|
|
9962
|
-
CLI version: ${JSON.parse((0,
|
|
9963
|
-
if ((0,
|
|
10318
|
+
CLI version: ${JSON.parse((0, import_node_fs20.readFileSync)((0, import_node_path21.join)(ROOT, "package.json"), "utf8")).version}`);
|
|
10319
|
+
if ((0, import_node_fs20.existsSync)((0, import_node_path21.join)(dir, "runtime"))) {
|
|
9964
10320
|
try {
|
|
9965
|
-
console.log(`Runtime: rigscope ${runtimeVersion((0,
|
|
10321
|
+
console.log(`Runtime: rigscope ${runtimeVersion((0, import_node_path21.join)(dir, "runtime"))}`);
|
|
9966
10322
|
} catch {
|
|
9967
10323
|
console.log("Runtime: invalid (run rigscope doctor)");
|
|
9968
10324
|
}
|
|
9969
10325
|
}
|
|
9970
|
-
if ((0,
|
|
10326
|
+
if ((0, import_node_fs20.existsSync)((0, import_node_path21.join)(dir, "runtime-previous"))) {
|
|
9971
10327
|
try {
|
|
9972
|
-
console.log(`Previous runtime: rigscope ${runtimeVersion((0,
|
|
10328
|
+
console.log(`Previous runtime: rigscope ${runtimeVersion((0, import_node_path21.join)(dir, "runtime-previous"))}`);
|
|
9973
10329
|
} catch {
|
|
9974
10330
|
console.log("Previous runtime: invalid");
|
|
9975
10331
|
}
|
|
9976
10332
|
}
|
|
9977
10333
|
const releaseState = readRuntimeState(dir);
|
|
9978
|
-
const paired = releaseState ? Object.values(releaseState.backups).filter((record) => (0,
|
|
10334
|
+
const paired = releaseState ? Object.values(releaseState.backups).filter((record) => (0, import_node_fs20.existsSync)(record.path)) : [];
|
|
9979
10335
|
if (paired.length > 0) console.log(`Paired database backups: ${paired.length}`);
|
|
9980
10336
|
const hubConfigured2 = config.users.length > 0;
|
|
9981
10337
|
if (hubConfigured2) console.log(`Hub: ${config.origin ?? `http://127.0.0.1:${config.port}`}`);
|
|
@@ -9984,8 +10340,8 @@ CLI version: ${JSON.parse((0, import_node_fs19.readFileSync)((0, import_node_pat
|
|
|
9984
10340
|
console.log(`Health: ${health.ok ? "ok" : health.error}
|
|
9985
10341
|
Running version: ${health.body?.version ?? "unavailable"}`);
|
|
9986
10342
|
}
|
|
9987
|
-
const state = (0,
|
|
9988
|
-
if ((0,
|
|
10343
|
+
const state = (0, import_node_path21.join)(dir, "collector", "state.json");
|
|
10344
|
+
if ((0, import_node_fs20.existsSync)(state)) {
|
|
9989
10345
|
const saved = JSON.parse(readPrivate(state));
|
|
9990
10346
|
console.log(`Destinations: ${saved.destinations.length}/8${saved.destinations.length === 0 ? " (awaiting connection)" : ""}`);
|
|
9991
10347
|
for (const destination of saved.destinations) console.log(` ${destination.url}`);
|
|
@@ -10035,9 +10391,9 @@ Running version: ${health.body?.version ?? "unavailable"}`);
|
|
|
10035
10391
|
return 0;
|
|
10036
10392
|
}
|
|
10037
10393
|
if (command === "upgrade") {
|
|
10038
|
-
if (!(0,
|
|
10394
|
+
if (!(0, import_node_fs20.existsSync)((0, import_node_path21.join)(dir, "runtime"))) throw new Error("Install a managed runtime before upgrading.");
|
|
10039
10395
|
console.log("Staging upgrade\u2026");
|
|
10040
|
-
const source = values.from ? /^[./]/.test(values.from) ? (0,
|
|
10396
|
+
const source = values.from ? /^[./]/.test(values.from) ? (0, import_node_path21.resolve)(values.from) : values.from : "rigscope@latest";
|
|
10041
10397
|
const report = await upgradeInstallation({
|
|
10042
10398
|
root: ROOT,
|
|
10043
10399
|
dir,
|
|
@@ -10049,13 +10405,14 @@ Running version: ${health.body?.version ?? "unavailable"}`);
|
|
|
10049
10405
|
if (report.schemaVersion !== null) console.log(`Database schema: ${report.schemaVersion}`);
|
|
10050
10406
|
if (report.verification.health) console.log(`Health: ${report.verification.health.attempts} probe(s) in ${report.verification.health.elapsedMs}ms`);
|
|
10051
10407
|
else console.log("Health: skipped because the service was inactive; start it explicitly.");
|
|
10408
|
+
printMachineDataOutcome2(report.machineHistory);
|
|
10052
10409
|
return 0;
|
|
10053
10410
|
}
|
|
10054
10411
|
if (command === "rollback") {
|
|
10055
10412
|
console.log("Rolling back\u2026");
|
|
10056
10413
|
const report = await rollbackInstallation({
|
|
10057
10414
|
dir,
|
|
10058
|
-
backup: values.backup ? (0,
|
|
10415
|
+
backup: values.backup ? (0, import_node_path21.resolve)(values.backup) : void 0,
|
|
10059
10416
|
healthDeadlineMs: healthDeadline(values.timeout)
|
|
10060
10417
|
});
|
|
10061
10418
|
printSuccess(`Rolled back: rigscope ${report.version} (previous ${report.previousVersion}).`);
|
|
@@ -10073,7 +10430,7 @@ Running version: ${health.body?.version ?? "unavailable"}`);
|
|
|
10073
10430
|
if (!componentEnabled(config, "hub")) throw new Error("This installation has no hub component.");
|
|
10074
10431
|
const password = recoveryPassword;
|
|
10075
10432
|
const report = await recoverAdminPassword({
|
|
10076
|
-
database: (0,
|
|
10433
|
+
database: (0, import_node_path21.join)(dir, "hub", "telemetry.sqlite"),
|
|
10077
10434
|
username: values.user ?? "owner",
|
|
10078
10435
|
password,
|
|
10079
10436
|
enable: values.enable === true
|