rigscope 0.2.0 → 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 +2 -2
- 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 +2 -2
- package/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- 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 +2 -2
- package/.next/server/app/administration.segments/_full.segment.rsc +2 -2
- package/.next/server/app/administration.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/administration.segments/administration/__PAGE__.segment.rsc +2 -2
- 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 +2 -2
- package/.next/server/app/alerts.segments/_full.segment.rsc +2 -2
- package/.next/server/app/alerts.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/alerts.segments/alerts/__PAGE__.segment.rsc +2 -2
- 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 +3 -3
- package/.next/server/app/connections.segments/_full.segment.rsc +3 -3
- package/.next/server/app/connections.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/connections.segments/connections/__PAGE__.segment.rsc +3 -3
- 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 +2 -2
- package/.next/server/app/history.segments/_full.segment.rsc +2 -2
- package/.next/server/app/history.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/history.segments/history/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/index.html +1 -1
- package/.next/server/app/index.rsc +2 -2
- package/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/index.segments/_full.segment.rsc +2 -2
- package/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- 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 +2 -2
- package/.next/server/app/login.segments/_full.segment.rsc +2 -2
- package/.next/server/app/login.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +2 -2
- 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 +2 -2
- package/.next/server/app/processes.segments/_full.segment.rsc +2 -2
- package/.next/server/app/processes.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/processes.segments/processes/__PAGE__.segment.rsc +2 -2
- package/.next/server/app-paths-manifest.json +2 -2
- package/.next/server/chunks/161.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/939-92930fde48061e20.js +1 -0
- package/.next/static/chunks/app/connections/page-7d18b901f2338f20.js +1 -0
- package/ARCHITECTURE.md +18 -6
- package/CHANGELOG.md +35 -0
- package/dist/cli.cjs +762 -509
- package/dist/collector.cjs +581 -115
- package/dist/hub.cjs +7 -3
- package/dist/system.cjs +1257 -363
- package/docs/configuration.md +1 -0
- package/docs/installation.md +9 -3
- package/docs/monitoring.md +6 -3
- package/docs/operations.md +40 -13
- package/docs/system-installation.md +11 -4
- package/docs/telemetry-storage.md +80 -9
- package/package.json +1 -1
- package/packaging/collector.env.example +6 -0
- package/packaging/system/rigscope-collector.service.example +3 -0
- package/.next/static/chunks/939-514e554087419c71.js +0 -1
- package/.next/static/chunks/app/connections/page-75abd16fc495fcbd.js +0 -1
- /package/.next/static/{Jlbibe2_iFCljUO4-BUK7 → JbaLjudQSxrMUD_VHPrnD}/_buildManifest.js +0 -0
- /package/.next/static/{Jlbibe2_iFCljUO4-BUK7 → 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
|
|
|
@@ -3624,17 +3641,17 @@ function uninstallInstallation(dir, purge = true, injected = {}) {
|
|
|
3624
3641
|
|
|
3625
3642
|
// src/cli/mutation.ts
|
|
3626
3643
|
var import_node_child_process3 = require("node:child_process");
|
|
3627
|
-
var
|
|
3628
|
-
var
|
|
3644
|
+
var import_node_fs14 = require("node:fs");
|
|
3645
|
+
var import_node_path15 = require("node:path");
|
|
3629
3646
|
var import_promises = require("node:readline/promises");
|
|
3630
3647
|
|
|
3631
3648
|
// src/cli/lifecycle.ts
|
|
3632
|
-
var
|
|
3633
|
-
var
|
|
3649
|
+
var import_node_fs13 = require("node:fs");
|
|
3650
|
+
var import_node_path14 = require("node:path");
|
|
3634
3651
|
|
|
3635
3652
|
// src/cli/upgrade.ts
|
|
3636
|
-
var
|
|
3637
|
-
var
|
|
3653
|
+
var import_node_fs12 = require("node:fs");
|
|
3654
|
+
var import_node_path13 = require("node:path");
|
|
3638
3655
|
|
|
3639
3656
|
// src/operations/database.ts
|
|
3640
3657
|
var import_node_fs10 = require("node:fs");
|
|
@@ -3982,6 +3999,187 @@ async function restoreDatabase(options) {
|
|
|
3982
3999
|
throw error2;
|
|
3983
4000
|
}
|
|
3984
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
|
+
}
|
|
3985
4183
|
|
|
3986
4184
|
// src/cli/health.ts
|
|
3987
4185
|
var import_node_http2 = require("node:http");
|
|
@@ -4175,6 +4373,7 @@ function dependencies(deps = {}) {
|
|
|
4175
4373
|
restore: deps.restore ?? restoreDatabase,
|
|
4176
4374
|
inspect: deps.inspect ?? inspectDatabase,
|
|
4177
4375
|
inspectRuntime: deps.inspectRuntime ?? inspectDatabaseWithRuntime,
|
|
4376
|
+
clearHistory: deps.clearHistory ?? clearMachineHistory,
|
|
4178
4377
|
waitHealth: deps.waitHealth ?? waitForHealth,
|
|
4179
4378
|
activate: deps.activate ?? activatePackage,
|
|
4180
4379
|
swap: deps.swap ?? swapRuntimes,
|
|
@@ -4185,10 +4384,10 @@ function dependencies(deps = {}) {
|
|
|
4185
4384
|
function acquireInstallLocks(dir, acquireLease) {
|
|
4186
4385
|
const releases = [];
|
|
4187
4386
|
try {
|
|
4188
|
-
releases.push(acquireLease((0,
|
|
4189
|
-
releases.push(acquireLease((0,
|
|
4190
|
-
releases.push(acquireLease((0,
|
|
4191
|
-
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")));
|
|
4192
4391
|
} catch (error2) {
|
|
4193
4392
|
for (const release of releases.reverse()) {
|
|
4194
4393
|
try {
|
|
@@ -4254,8 +4453,11 @@ function assertComponentsStopped(dir, deps, components) {
|
|
|
4254
4453
|
}
|
|
4255
4454
|
}
|
|
4256
4455
|
}
|
|
4456
|
+
function machineDataPaths(dir) {
|
|
4457
|
+
return { database: databasePath(dir), queueTree: (0, import_node_path13.join)(dir, "collector", "outbox") };
|
|
4458
|
+
}
|
|
4257
4459
|
function collectorStateCheck(dir) {
|
|
4258
|
-
const path2 = (0,
|
|
4460
|
+
const path2 = (0, import_node_path13.join)(dir, "collector", "state.json");
|
|
4259
4461
|
let raw;
|
|
4260
4462
|
try {
|
|
4261
4463
|
raw = readPrivate(path2);
|
|
@@ -4279,13 +4481,13 @@ function hubTarget(config, dir) {
|
|
|
4279
4481
|
role: "hub",
|
|
4280
4482
|
port: config.port,
|
|
4281
4483
|
origin: config.origin,
|
|
4282
|
-
socket: config.socket ?? (0,
|
|
4484
|
+
socket: config.socket ?? (0, import_node_path13.join)(dir, "run", "hub.sock")
|
|
4283
4485
|
});
|
|
4284
4486
|
}
|
|
4285
4487
|
async function verifyRunningInstallation(options) {
|
|
4286
4488
|
const d = dependencies(options.deps);
|
|
4287
4489
|
const deadline = Date.now() + (options.deadlineMs ?? DEFAULT_HEALTH_DEADLINE_MS);
|
|
4288
|
-
const runtime = (0,
|
|
4490
|
+
const runtime = (0, import_node_path13.join)(options.dir, "runtime");
|
|
4289
4491
|
const version = runtimeVersion(runtime);
|
|
4290
4492
|
if (version !== options.expectedVersion) {
|
|
4291
4493
|
throw new OperationsError(
|
|
@@ -4326,7 +4528,7 @@ async function verifyRunningInstallation(options) {
|
|
|
4326
4528
|
}
|
|
4327
4529
|
}
|
|
4328
4530
|
const path2 = databasePath(options.dir);
|
|
4329
|
-
if (!(0,
|
|
4531
|
+
if (!(0, import_node_fs12.existsSync)(path2)) {
|
|
4330
4532
|
if (status.active) {
|
|
4331
4533
|
throw new OperationsError("database-missing", `hub database is missing after activation: ${path2}`);
|
|
4332
4534
|
}
|
|
@@ -4366,8 +4568,8 @@ async function verifyRunningInstallation(options) {
|
|
|
4366
4568
|
let problem = "collector has not sampled";
|
|
4367
4569
|
while (Date.now() < deadline) {
|
|
4368
4570
|
try {
|
|
4369
|
-
const marker = JSON.parse(readPrivate((0,
|
|
4370
|
-
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")));
|
|
4371
4573
|
if (marker.version !== options.expectedVersion) throw new Error("collector version does not match the activated release");
|
|
4372
4574
|
if (marker.pid !== owner.pid || !Number.isSafeInteger(marker.pid)) throw new Error("collector readiness belongs to another process");
|
|
4373
4575
|
process.kill(marker.pid, 0);
|
|
@@ -4385,7 +4587,7 @@ async function verifyRunningInstallation(options) {
|
|
|
4385
4587
|
return { version, health, database };
|
|
4386
4588
|
}
|
|
4387
4589
|
async function recoverActivation(options) {
|
|
4388
|
-
const runtime = (0,
|
|
4590
|
+
const runtime = (0, import_node_path13.join)(options.dir, "runtime");
|
|
4389
4591
|
const messages = [];
|
|
4390
4592
|
let releaseLocks = null;
|
|
4391
4593
|
try {
|
|
@@ -4394,12 +4596,16 @@ async function recoverActivation(options) {
|
|
|
4394
4596
|
if (status.active) options.deps.service.stop(options.dir, component);
|
|
4395
4597
|
}
|
|
4396
4598
|
assertComponentsStopped(options.dir, options.deps, COMPONENT_LIST);
|
|
4397
|
-
if ((0,
|
|
4599
|
+
if ((0, import_node_fs12.existsSync)(databasePath(options.dir))) assertNoActiveHubLock(databasePath(options.dir));
|
|
4398
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
|
+
}
|
|
4399
4605
|
if (options.activated) {
|
|
4400
4606
|
try {
|
|
4401
|
-
if ((0,
|
|
4402
|
-
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"));
|
|
4403
4609
|
if (restoredVersion !== options.previousVersion) {
|
|
4404
4610
|
throw new Error(`restored runtime reports ${restoredVersion}, expected ${options.previousVersion}`);
|
|
4405
4611
|
}
|
|
@@ -4410,10 +4616,11 @@ async function recoverActivation(options) {
|
|
|
4410
4616
|
}
|
|
4411
4617
|
}
|
|
4412
4618
|
const path2 = databasePath(options.dir);
|
|
4413
|
-
|
|
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)) {
|
|
4414
4621
|
try {
|
|
4415
|
-
const old = options.deps.inspectRuntime((0,
|
|
4416
|
-
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) {
|
|
4417
4624
|
const restored = await options.deps.restore({
|
|
4418
4625
|
input: options.backupPath,
|
|
4419
4626
|
database: path2,
|
|
@@ -4430,16 +4637,16 @@ async function recoverActivation(options) {
|
|
|
4430
4637
|
messages.push(`database recovery failed: ${errorMessage(error2)}; pre-upgrade copy is ${options.backupPath}`);
|
|
4431
4638
|
return messages.join("; ");
|
|
4432
4639
|
}
|
|
4433
|
-
} else if (options.backupPath === null && (0,
|
|
4640
|
+
} else if (options.backupPath === null && (0, import_node_fs12.existsSync)(path2)) {
|
|
4434
4641
|
try {
|
|
4435
|
-
const old = options.deps.inspectRuntime((0,
|
|
4642
|
+
const old = options.deps.inspectRuntime((0, import_node_path13.join)(options.dir, "runtime"), path2);
|
|
4436
4643
|
if (!old.integrityOk || old.newerSchema || old.ledgerProblem !== null) {
|
|
4437
|
-
const backups = (0,
|
|
4644
|
+
const backups = (0, import_node_path13.join)(options.dir, "backups");
|
|
4438
4645
|
ensurePrivateDir(backups);
|
|
4439
|
-
const preserved = (0,
|
|
4440
|
-
(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);
|
|
4441
4648
|
for (const sidecar of [`${path2}-wal`, `${path2}-shm`]) {
|
|
4442
|
-
if ((0,
|
|
4649
|
+
if ((0, import_node_fs12.existsSync)(sidecar)) (0, import_node_fs12.renameSync)(sidecar, `${preserved}${sidecar.slice(path2.length)}`);
|
|
4443
4650
|
}
|
|
4444
4651
|
messages.push(`preserved the failed activation database at ${preserved}; the previous runtime will create a fresh database`);
|
|
4445
4652
|
} else {
|
|
@@ -4483,8 +4690,8 @@ async function upgradeInstallation(options, injected = {}) {
|
|
|
4483
4690
|
const deps = dependencies(injected);
|
|
4484
4691
|
const config = readSetup(options.dir);
|
|
4485
4692
|
if (!config) throw new OperationsError("not-installed", "No installation found. Run rigscope install first.");
|
|
4486
|
-
const runtime = (0,
|
|
4487
|
-
if (!(0,
|
|
4693
|
+
const runtime = (0, import_node_path13.join)(options.dir, "runtime");
|
|
4694
|
+
if (!(0, import_node_fs12.existsSync)(runtime)) {
|
|
4488
4695
|
throw new OperationsError("not-installed", "Install a managed runtime before upgrading.");
|
|
4489
4696
|
}
|
|
4490
4697
|
const currentVersion = runtimeVersion(runtime);
|
|
@@ -4497,7 +4704,7 @@ async function upgradeInstallation(options, injected = {}) {
|
|
|
4497
4704
|
expectedVersion = runtimeVersion(stage);
|
|
4498
4705
|
assertRuntimeArtifacts(stage, "staged runtime");
|
|
4499
4706
|
const path2 = databasePath(options.dir);
|
|
4500
|
-
if ((0,
|
|
4707
|
+
if ((0, import_node_fs12.existsSync)(path2)) {
|
|
4501
4708
|
const staged = deps.inspectRuntime(stage, path2);
|
|
4502
4709
|
if (!staged.integrityOk) {
|
|
4503
4710
|
throw new OperationsError("database-integrity", `database integrity check failed before upgrade: ${path2}`);
|
|
@@ -4514,26 +4721,27 @@ async function upgradeInstallation(options, injected = {}) {
|
|
|
4514
4721
|
expectedSchema = staged.supportedSchemaVersion;
|
|
4515
4722
|
}
|
|
4516
4723
|
} catch (error2) {
|
|
4517
|
-
(0,
|
|
4724
|
+
(0, import_node_fs12.rmSync)(stage, { recursive: true, force: true });
|
|
4518
4725
|
throw error2;
|
|
4519
4726
|
}
|
|
4520
4727
|
const snapshot = snapshotComponents(options.dir, deps);
|
|
4521
4728
|
const running = snapshot.running;
|
|
4522
4729
|
let releaseLocks = null;
|
|
4523
|
-
const releaseOperation = deps.acquireLease((0,
|
|
4730
|
+
const releaseOperation = deps.acquireLease((0, import_node_path13.join)(options.dir, "run", "operation.lock"));
|
|
4524
4731
|
let backupPath = null;
|
|
4525
4732
|
let activated = false;
|
|
4733
|
+
let machineData = null;
|
|
4526
4734
|
try {
|
|
4527
4735
|
stopComponents(options.dir, deps, running);
|
|
4528
4736
|
assertComponentsStopped(options.dir, deps, running);
|
|
4529
|
-
if (running.includes("hub") || componentEnabled(config, "hub") || (0,
|
|
4737
|
+
if (running.includes("hub") || componentEnabled(config, "hub") || (0, import_node_fs12.existsSync)(databasePath(options.dir))) {
|
|
4530
4738
|
assertNoActiveHubLock(databasePath(options.dir));
|
|
4531
4739
|
}
|
|
4532
4740
|
releaseLocks = acquireInstallLocks(options.dir, deps.acquireLease);
|
|
4533
|
-
if ((0,
|
|
4534
|
-
const backups = (0,
|
|
4741
|
+
if ((0, import_node_fs12.existsSync)(databasePath(options.dir))) {
|
|
4742
|
+
const backups = (0, import_node_path13.join)(options.dir, "backups");
|
|
4535
4743
|
ensurePrivateDir(backups);
|
|
4536
|
-
backupPath = (0,
|
|
4744
|
+
backupPath = (0, import_node_path13.join)(
|
|
4537
4745
|
backups,
|
|
4538
4746
|
`pre-upgrade-${currentVersion}-to-${expectedVersion}-${timestampSlug(deps.now())}.sqlite`
|
|
4539
4747
|
);
|
|
@@ -4562,6 +4770,9 @@ async function upgradeInstallation(options, injected = {}) {
|
|
|
4562
4770
|
}
|
|
4563
4771
|
deps.activate(options.dir, stage);
|
|
4564
4772
|
activated = true;
|
|
4773
|
+
machineData = performMachineDataCleanup(options.dir, machineDataPaths(options.dir), deps.now, {
|
|
4774
|
+
clear: deps.clearHistory
|
|
4775
|
+
});
|
|
4565
4776
|
releaseLocks();
|
|
4566
4777
|
releaseLocks = null;
|
|
4567
4778
|
for (const component of running) deps.service.start(options.dir, component);
|
|
@@ -4577,7 +4788,7 @@ async function upgradeInstallation(options, injected = {}) {
|
|
|
4577
4788
|
});
|
|
4578
4789
|
restoreStartup(options.dir, deps, snapshot.enabled, false);
|
|
4579
4790
|
const now = new Date(deps.now()).toISOString();
|
|
4580
|
-
if (backupPath !== null && (0,
|
|
4791
|
+
if (backupPath !== null && (0, import_node_fs12.existsSync)(backupPath)) {
|
|
4581
4792
|
const info = deps.inspect(backupPath);
|
|
4582
4793
|
const record = {
|
|
4583
4794
|
path: backupPath,
|
|
@@ -4601,13 +4812,15 @@ async function upgradeInstallation(options, injected = {}) {
|
|
|
4601
4812
|
activatedAt: now
|
|
4602
4813
|
}
|
|
4603
4814
|
});
|
|
4815
|
+
completeMachineDataCleanup(options.dir, machineData, expectedVersion);
|
|
4604
4816
|
return {
|
|
4605
4817
|
version: expectedVersion,
|
|
4606
4818
|
previousVersion: currentVersion,
|
|
4607
4819
|
backupPath,
|
|
4608
4820
|
schemaVersion: verification.database?.schemaVersion ?? expectedSchema,
|
|
4609
4821
|
serviceRestarted: running.length > 0,
|
|
4610
|
-
verification
|
|
4822
|
+
verification,
|
|
4823
|
+
machineHistory: machineData.report
|
|
4611
4824
|
};
|
|
4612
4825
|
} catch (error2) {
|
|
4613
4826
|
releaseLocks?.();
|
|
@@ -4617,6 +4830,7 @@ async function upgradeInstallation(options, injected = {}) {
|
|
|
4617
4830
|
config,
|
|
4618
4831
|
previousVersion: currentVersion,
|
|
4619
4832
|
backupPath,
|
|
4833
|
+
machineData,
|
|
4620
4834
|
running,
|
|
4621
4835
|
startup: snapshot.enabled,
|
|
4622
4836
|
activated,
|
|
@@ -4630,13 +4844,13 @@ async function upgradeInstallation(options, injected = {}) {
|
|
|
4630
4844
|
} finally {
|
|
4631
4845
|
releaseLocks?.();
|
|
4632
4846
|
releaseOperation();
|
|
4633
|
-
if ((0,
|
|
4847
|
+
if ((0, import_node_fs12.existsSync)(stage)) (0, import_node_fs12.rmSync)(stage, { recursive: true, force: true });
|
|
4634
4848
|
}
|
|
4635
4849
|
}
|
|
4636
4850
|
function rollbackBackup(options) {
|
|
4637
4851
|
if (options.explicitBackup !== void 0) {
|
|
4638
4852
|
const path2 = options.explicitBackup;
|
|
4639
|
-
if (!(0,
|
|
4853
|
+
if (!(0, import_node_fs12.existsSync)(path2)) {
|
|
4640
4854
|
throw new OperationsError("backup-missing", `rollback backup does not exist: ${path2}`);
|
|
4641
4855
|
}
|
|
4642
4856
|
const info2 = options.deps.inspect(path2);
|
|
@@ -4655,7 +4869,7 @@ function rollbackBackup(options) {
|
|
|
4655
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`
|
|
4656
4870
|
);
|
|
4657
4871
|
}
|
|
4658
|
-
if (!(0,
|
|
4872
|
+
if (!(0, import_node_fs12.existsSync)(recorded.path)) {
|
|
4659
4873
|
throw new OperationsError(
|
|
4660
4874
|
"backup-missing",
|
|
4661
4875
|
`paired pre-upgrade backup for ${options.currentVersion} is missing: ${recorded.path}`
|
|
@@ -4677,10 +4891,10 @@ async function rollbackInstallation(options, injected = {}) {
|
|
|
4677
4891
|
const deps = dependencies(injected);
|
|
4678
4892
|
const config = readSetup(options.dir);
|
|
4679
4893
|
if (!config) throw new OperationsError("not-installed", "No installation found. Run rigscope install first.");
|
|
4680
|
-
const runtime = (0,
|
|
4681
|
-
const previousRuntime = (0,
|
|
4682
|
-
if (!(0,
|
|
4683
|
-
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)) {
|
|
4684
4898
|
throw new OperationsError("no-previous-release", "No previous runtime is available for rollback.");
|
|
4685
4899
|
}
|
|
4686
4900
|
const currentVersion = runtimeVersion(runtime);
|
|
@@ -4691,19 +4905,19 @@ async function rollbackInstallation(options, injected = {}) {
|
|
|
4691
4905
|
const snapshot = snapshotComponents(options.dir, deps);
|
|
4692
4906
|
const running = snapshot.running;
|
|
4693
4907
|
let releaseLocks = null;
|
|
4694
|
-
const releaseOperation = deps.acquireLease((0,
|
|
4908
|
+
const releaseOperation = deps.acquireLease((0, import_node_path13.join)(options.dir, "run", "operation.lock"));
|
|
4695
4909
|
let restoredBackup = null;
|
|
4696
4910
|
let preRestoreBackup = null;
|
|
4697
4911
|
let swapped = false;
|
|
4698
4912
|
try {
|
|
4699
4913
|
stopComponents(options.dir, deps, running);
|
|
4700
4914
|
assertComponentsStopped(options.dir, deps, running);
|
|
4701
|
-
if (running.includes("hub") || componentEnabled(config, "hub") || (0,
|
|
4915
|
+
if (running.includes("hub") || componentEnabled(config, "hub") || (0, import_node_fs12.existsSync)(databasePath(options.dir))) {
|
|
4702
4916
|
assertNoActiveHubLock(databasePath(options.dir));
|
|
4703
4917
|
}
|
|
4704
4918
|
releaseLocks = acquireInstallLocks(options.dir, deps.acquireLease);
|
|
4705
4919
|
const path2 = databasePath(options.dir);
|
|
4706
|
-
if ((0,
|
|
4920
|
+
if ((0, import_node_fs12.existsSync)(path2)) {
|
|
4707
4921
|
const previousSupport = deps.inspectRuntime(previousRuntime, path2);
|
|
4708
4922
|
if (!previousSupport.integrityOk || previousSupport.newerSchema || previousSupport.ledgerProblem !== null) {
|
|
4709
4923
|
const backup3 = rollbackBackup({
|
|
@@ -4774,7 +4988,7 @@ async function rollbackInstallation(options, injected = {}) {
|
|
|
4774
4988
|
if (status.active) deps.service.stop(options.dir, component);
|
|
4775
4989
|
}
|
|
4776
4990
|
assertComponentsStopped(options.dir, deps, COMPONENT_LIST);
|
|
4777
|
-
if ((0,
|
|
4991
|
+
if ((0, import_node_fs12.existsSync)(databasePath(options.dir))) assertNoActiveHubLock(databasePath(options.dir));
|
|
4778
4992
|
releaseLocks = acquireInstallLocks(options.dir, deps.acquireLease);
|
|
4779
4993
|
} catch (stopError) {
|
|
4780
4994
|
throw new OperationsError("rollback-failed", `rollback failed: ${errorMessage(error2)}. Recovery refused while runtime ownership is uncertain: ${errorMessage(stopError)}`, { cause: error2 });
|
|
@@ -4788,7 +5002,7 @@ async function rollbackInstallation(options, injected = {}) {
|
|
|
4788
5002
|
safeToRestart = false;
|
|
4789
5003
|
}
|
|
4790
5004
|
}
|
|
4791
|
-
if (preRestoreBackup !== null && (0,
|
|
5005
|
+
if (preRestoreBackup !== null && (0, import_node_fs12.existsSync)(preRestoreBackup)) {
|
|
4792
5006
|
try {
|
|
4793
5007
|
await deps.restore({
|
|
4794
5008
|
input: preRestoreBackup,
|
|
@@ -4803,7 +5017,7 @@ async function rollbackInstallation(options, injected = {}) {
|
|
|
4803
5017
|
safeToRestart = false;
|
|
4804
5018
|
}
|
|
4805
5019
|
}
|
|
4806
|
-
if (safeToRestart && running.includes("hub") && (0,
|
|
5020
|
+
if (safeToRestart && running.includes("hub") && (0, import_node_fs12.existsSync)(databasePath(options.dir))) {
|
|
4807
5021
|
try {
|
|
4808
5022
|
const info = deps.inspectRuntime(runtime, databasePath(options.dir));
|
|
4809
5023
|
if (!info.integrityOk || info.newerSchema || info.ledgerProblem !== null) throw new Error("runtime/database compatibility is not established");
|
|
@@ -4850,17 +5064,17 @@ async function rollbackInstallation(options, injected = {}) {
|
|
|
4850
5064
|
|
|
4851
5065
|
// src/cli/lifecycle.ts
|
|
4852
5066
|
function collectorEnrolled(dir) {
|
|
4853
|
-
const path2 = (0,
|
|
4854
|
-
if (!(0,
|
|
5067
|
+
const path2 = (0, import_node_path14.join)(dir, "collector", "state.json");
|
|
5068
|
+
if (!(0, import_node_fs13.existsSync)(path2)) return false;
|
|
4855
5069
|
const state = JSON.parse(readPrivate(path2));
|
|
4856
5070
|
return Array.isArray(state.destinations) && state.destinations.length > 0;
|
|
4857
5071
|
}
|
|
4858
5072
|
var AWAITING_CONNECTION = "Collector is awaiting connection. Run rigscope connect https://your-hub first.";
|
|
4859
5073
|
function assertNoCompetingRuntime(dir, component) {
|
|
4860
5074
|
const locks = [
|
|
4861
|
-
(0,
|
|
4862
|
-
(0,
|
|
4863
|
-
...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")] : []
|
|
4864
5078
|
];
|
|
4865
5079
|
const releases = [];
|
|
4866
5080
|
try {
|
|
@@ -4879,11 +5093,11 @@ function assertNoCompetingRuntime(dir, component) {
|
|
|
4879
5093
|
async function startInstallation(dir, component, injected = {}) {
|
|
4880
5094
|
const config = readSetup(dir);
|
|
4881
5095
|
if (!config) throw new Error("No background service installed. Run rigscope install first.");
|
|
4882
|
-
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.");
|
|
4883
5097
|
const selected = component ? [component] : enabledComponents(config);
|
|
4884
5098
|
if (selected.length === 0) throw new Error("No enabled components. Run rigscope enable hub or rigscope enable collector.");
|
|
4885
5099
|
for (const target of selected) {
|
|
4886
|
-
if (!(0,
|
|
5100
|
+
if (!(0, import_node_fs13.existsSync)(unitPath(dir, target))) throw new Error("No background service installed. Run rigscope install first.");
|
|
4887
5101
|
}
|
|
4888
5102
|
const status = injected.status ?? serviceStatus;
|
|
4889
5103
|
const start = injected.start ?? systemctl;
|
|
@@ -4911,7 +5125,7 @@ async function startInstallation(dir, component, injected = {}) {
|
|
|
4911
5125
|
await (injected.verify ?? verifyRunningInstallation)({
|
|
4912
5126
|
dir,
|
|
4913
5127
|
config,
|
|
4914
|
-
expectedVersion: runtimeVersion((0,
|
|
5128
|
+
expectedVersion: runtimeVersion((0, import_node_path14.join)(dir, "runtime")),
|
|
4915
5129
|
components: started,
|
|
4916
5130
|
requireActive: started
|
|
4917
5131
|
});
|
|
@@ -4995,11 +5209,11 @@ function printHelp(message, options = {}) {
|
|
|
4995
5209
|
|
|
4996
5210
|
// src/cli/mutation.ts
|
|
4997
5211
|
async function resumeComponent(dir, component) {
|
|
4998
|
-
if ((0,
|
|
4999
|
-
const run = (0,
|
|
5000
|
-
(0,
|
|
5001
|
-
const log = (0,
|
|
5002
|
-
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);
|
|
5003
5217
|
let child;
|
|
5004
5218
|
try {
|
|
5005
5219
|
child = (0, import_node_child_process3.spawn)(process.execPath, [process.argv[1], "run", component, "--state-dir", dir], {
|
|
@@ -5008,7 +5222,7 @@ async function resumeComponent(dir, component) {
|
|
|
5008
5222
|
env: process.env
|
|
5009
5223
|
});
|
|
5010
5224
|
} finally {
|
|
5011
|
-
(0,
|
|
5225
|
+
(0, import_node_fs14.closeSync)(fd);
|
|
5012
5226
|
}
|
|
5013
5227
|
let failure;
|
|
5014
5228
|
child.on("error", (error2) => {
|
|
@@ -5019,7 +5233,7 @@ async function resumeComponent(dir, component) {
|
|
|
5019
5233
|
while (Date.now() < deadline) {
|
|
5020
5234
|
if (failure || child.exitCode !== null || child.signalCode !== null) break;
|
|
5021
5235
|
try {
|
|
5022
|
-
const owner = JSON.parse((0,
|
|
5236
|
+
const owner = JSON.parse((0, import_node_fs14.readFileSync)((0, import_node_path15.join)(run, `${component}.lock`), "utf8"));
|
|
5023
5237
|
if (owner.pid === child.pid) return "started";
|
|
5024
5238
|
} catch {
|
|
5025
5239
|
}
|
|
@@ -5075,12 +5289,20 @@ async function prepareMutation(dir, selected, options, deps = {}) {
|
|
|
5075
5289
|
|
|
5076
5290
|
// src/cli/runtime.ts
|
|
5077
5291
|
var import_node_child_process4 = require("node:child_process");
|
|
5078
|
-
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
|
+
}
|
|
5079
5301
|
function componentLeasePath(dir, component) {
|
|
5080
|
-
return (0,
|
|
5302
|
+
return (0, import_node_path16.join)(dir, "run", `${component}.lock`);
|
|
5081
5303
|
}
|
|
5082
5304
|
function combinedLeasePath(dir) {
|
|
5083
|
-
return (0,
|
|
5305
|
+
return (0, import_node_path16.join)(dir, "run", "rigscope.lock");
|
|
5084
5306
|
}
|
|
5085
5307
|
function label(component) {
|
|
5086
5308
|
return component === "hub" ? "Hub" : "Collector";
|
|
@@ -5097,6 +5319,7 @@ async function runInstallation(root, dir, component) {
|
|
|
5097
5319
|
console.error("No components are enabled. Run rigscope enable hub or rigscope enable collector.");
|
|
5098
5320
|
return 0;
|
|
5099
5321
|
}
|
|
5322
|
+
const collectorEnvironment = selected.includes("collector") ? collectorQueueModeEnvironment(process.env) : {};
|
|
5100
5323
|
if (selected.includes("collector") && !collectorHasDestinations(dir)) {
|
|
5101
5324
|
console.log("Collector awaiting connection. Run rigscope connect https://your-hub.");
|
|
5102
5325
|
const remaining = selected.filter((role) => role !== "collector");
|
|
@@ -5136,13 +5359,14 @@ async function runInstallation(root, dir, component) {
|
|
|
5136
5359
|
process.on("SIGTERM", signal);
|
|
5137
5360
|
process.on("SIGINT", signal);
|
|
5138
5361
|
function launch(role) {
|
|
5139
|
-
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: {
|
|
5140
5363
|
...environment,
|
|
5141
5364
|
NODE_ENV: "production",
|
|
5142
5365
|
...role === "hub" ? hubEnvironment(dir, config) : {
|
|
5143
5366
|
COLLECTOR_MODE: "real",
|
|
5144
|
-
COLLECTOR_STATE_FILE: (0,
|
|
5145
|
-
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
|
|
5146
5370
|
}
|
|
5147
5371
|
} });
|
|
5148
5372
|
children.add(child);
|
|
@@ -5169,8 +5393,8 @@ async function runInstallation(root, dir, component) {
|
|
|
5169
5393
|
}
|
|
5170
5394
|
|
|
5171
5395
|
// src/cli/doctor.ts
|
|
5172
|
-
var
|
|
5173
|
-
var
|
|
5396
|
+
var import_node_fs15 = require("node:fs");
|
|
5397
|
+
var import_node_path17 = require("node:path");
|
|
5174
5398
|
var DEFAULT_DEPENDENCIES = {
|
|
5175
5399
|
serviceStatus,
|
|
5176
5400
|
probeHealth,
|
|
@@ -5180,7 +5404,7 @@ var DEFAULT_DEPENDENCIES = {
|
|
|
5180
5404
|
inspectDatabase,
|
|
5181
5405
|
diskFree: (path2) => {
|
|
5182
5406
|
try {
|
|
5183
|
-
const stats = (0,
|
|
5407
|
+
const stats = (0, import_node_fs15.statfsSync)(path2);
|
|
5184
5408
|
return { free: Number(stats.bavail) * Number(stats.bsize), total: Number(stats.blocks) * Number(stats.bsize) };
|
|
5185
5409
|
} catch {
|
|
5186
5410
|
return null;
|
|
@@ -5189,13 +5413,13 @@ var DEFAULT_DEPENDENCIES = {
|
|
|
5189
5413
|
sensorReadable: (paths) => paths.filter((path2) => {
|
|
5190
5414
|
let fd;
|
|
5191
5415
|
try {
|
|
5192
|
-
fd = (0,
|
|
5193
|
-
(0,
|
|
5416
|
+
fd = (0, import_node_fs15.openSync)(path2, "r");
|
|
5417
|
+
(0, import_node_fs15.readSync)(fd, Buffer.alloc(1), 0, 1, 0);
|
|
5194
5418
|
return true;
|
|
5195
5419
|
} catch {
|
|
5196
5420
|
return false;
|
|
5197
5421
|
} finally {
|
|
5198
|
-
if (fd !== void 0) (0,
|
|
5422
|
+
if (fd !== void 0) (0, import_node_fs15.closeSync)(fd);
|
|
5199
5423
|
}
|
|
5200
5424
|
})
|
|
5201
5425
|
};
|
|
@@ -5257,10 +5481,10 @@ async function diagnoseInstallation(dir, injected = {}) {
|
|
|
5257
5481
|
}
|
|
5258
5482
|
for (const [id, label3, path2] of [
|
|
5259
5483
|
["state-dir", "State directory", dir],
|
|
5260
|
-
["config-mode", "Configuration permissions", (0,
|
|
5484
|
+
["config-mode", "Configuration permissions", (0, import_node_path17.join)(dir, "config.json")]
|
|
5261
5485
|
]) {
|
|
5262
5486
|
try {
|
|
5263
|
-
const stat = (0,
|
|
5487
|
+
const stat = (0, import_node_fs15.lstatSync)(path2);
|
|
5264
5488
|
const privateEntry = id === "state-dir" ? stat.isDirectory() : stat.isFile();
|
|
5265
5489
|
const privateMode = (stat.mode & 63) === 0;
|
|
5266
5490
|
add({
|
|
@@ -5275,7 +5499,7 @@ async function diagnoseInstallation(dir, injected = {}) {
|
|
|
5275
5499
|
}
|
|
5276
5500
|
}
|
|
5277
5501
|
let runtime = null;
|
|
5278
|
-
if (!(0,
|
|
5502
|
+
if (!(0, import_node_fs15.existsSync)((0, import_node_path17.join)(dir, "runtime"))) {
|
|
5279
5503
|
add({
|
|
5280
5504
|
id: "runtime",
|
|
5281
5505
|
label: "Runtime",
|
|
@@ -5285,9 +5509,9 @@ async function diagnoseInstallation(dir, injected = {}) {
|
|
|
5285
5509
|
});
|
|
5286
5510
|
} else {
|
|
5287
5511
|
try {
|
|
5288
|
-
assertRuntimeArtifacts((0,
|
|
5289
|
-
const version2 = runtimeVersion((0,
|
|
5290
|
-
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");
|
|
5291
5515
|
add({ id: "runtime", label: "Runtime", status: "ok", detail: `rigscope ${version2}` });
|
|
5292
5516
|
} catch (error2) {
|
|
5293
5517
|
add({
|
|
@@ -5299,9 +5523,9 @@ async function diagnoseInstallation(dir, injected = {}) {
|
|
|
5299
5523
|
});
|
|
5300
5524
|
}
|
|
5301
5525
|
}
|
|
5302
|
-
if ((0,
|
|
5526
|
+
if ((0, import_node_fs15.existsSync)((0, import_node_path17.join)(dir, "runtime-previous"))) {
|
|
5303
5527
|
try {
|
|
5304
|
-
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"))}` });
|
|
5305
5529
|
} catch (error2) {
|
|
5306
5530
|
add({ id: "previous-runtime", label: "Previous runtime", status: "warn", detail: errorText2(error2) });
|
|
5307
5531
|
}
|
|
@@ -5363,7 +5587,7 @@ async function diagnoseInstallation(dir, injected = {}) {
|
|
|
5363
5587
|
const collectorActive = services.collector.active;
|
|
5364
5588
|
if (hubEnabled || hubActive) {
|
|
5365
5589
|
const path2 = databasePath(dir);
|
|
5366
|
-
if (!(0,
|
|
5590
|
+
if (!(0, import_node_fs15.existsSync)(path2)) {
|
|
5367
5591
|
add({
|
|
5368
5592
|
id: "database",
|
|
5369
5593
|
label: "Database",
|
|
@@ -5392,7 +5616,7 @@ async function diagnoseInstallation(dir, injected = {}) {
|
|
|
5392
5616
|
});
|
|
5393
5617
|
}
|
|
5394
5618
|
}
|
|
5395
|
-
const space = deps.diskFree((0,
|
|
5619
|
+
const space = deps.diskFree((0, import_node_path17.join)(dir, "hub"));
|
|
5396
5620
|
if (space !== null) {
|
|
5397
5621
|
const free = space.free;
|
|
5398
5622
|
add({
|
|
@@ -5406,9 +5630,9 @@ async function diagnoseInstallation(dir, injected = {}) {
|
|
|
5406
5630
|
}
|
|
5407
5631
|
if (hubEnabled || hubActive) {
|
|
5408
5632
|
if (config.origin) {
|
|
5409
|
-
const socket = config.socket ?? (0,
|
|
5633
|
+
const socket = config.socket ?? (0, import_node_path17.join)(dir, "run", "hub.sock");
|
|
5410
5634
|
try {
|
|
5411
|
-
const stat = (0,
|
|
5635
|
+
const stat = (0, import_node_fs15.lstatSync)(socket);
|
|
5412
5636
|
add({
|
|
5413
5637
|
id: "socket",
|
|
5414
5638
|
label: "Unix socket",
|
|
@@ -5450,7 +5674,7 @@ async function diagnoseInstallation(dir, injected = {}) {
|
|
|
5450
5674
|
}
|
|
5451
5675
|
if (hubActive) {
|
|
5452
5676
|
try {
|
|
5453
|
-
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") });
|
|
5454
5678
|
const health = await deps.probeHealth(target, 3e3);
|
|
5455
5679
|
const expected = runtime ? runtimeVersion(runtime) : null;
|
|
5456
5680
|
const reported = typeof health.body?.version === "string" ? health.body.version : null;
|
|
@@ -5468,7 +5692,7 @@ async function diagnoseInstallation(dir, injected = {}) {
|
|
|
5468
5692
|
}
|
|
5469
5693
|
}
|
|
5470
5694
|
if (collectorEnabled || collectorActive) {
|
|
5471
|
-
const statePath = (0,
|
|
5695
|
+
const statePath = (0, import_node_path17.join)(dir, "collector", "state.json");
|
|
5472
5696
|
try {
|
|
5473
5697
|
const raw = readPrivate(statePath);
|
|
5474
5698
|
const state = JSON.parse(raw);
|
|
@@ -5543,17 +5767,17 @@ async function diagnoseInstallation(dir, injected = {}) {
|
|
|
5543
5767
|
function hubEnvironment2(dir, config) {
|
|
5544
5768
|
return {
|
|
5545
5769
|
...!config.origin ? { HUB_HOST: "127.0.0.1", HUB_PORT: String(config.port) } : {},
|
|
5546
|
-
HUB_STATE_FILE: (0,
|
|
5770
|
+
HUB_STATE_FILE: (0, import_node_path17.join)(dir, "hub", "enrollment.json"),
|
|
5547
5771
|
HUB_DATABASE_PATH: databasePath(dir),
|
|
5548
5772
|
HUB_BROWSER_USERS: JSON.stringify(config.users),
|
|
5549
5773
|
HUB_COLLECTORS: JSON.stringify(config.collectors),
|
|
5550
5774
|
...config.maxCollectorConnections === void 0 ? {} : { HUB_MAX_COLLECTOR_CONNECTIONS: String(config.maxCollectorConnections) },
|
|
5551
|
-
...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") } : {}
|
|
5552
5776
|
};
|
|
5553
5777
|
}
|
|
5554
5778
|
function collectorAwaiting(dir) {
|
|
5555
5779
|
try {
|
|
5556
|
-
const state = JSON.parse(readPrivate((0,
|
|
5780
|
+
const state = JSON.parse(readPrivate((0, import_node_path17.join)(dir, "collector", "state.json")));
|
|
5557
5781
|
return !Array.isArray(state.destinations) || state.destinations.length === 0;
|
|
5558
5782
|
} catch (error2) {
|
|
5559
5783
|
return error2.code === "ENOENT";
|
|
@@ -5565,13 +5789,13 @@ function powerCounterPaths() {
|
|
|
5565
5789
|
if (depth > 3 || paths.length >= 64) return;
|
|
5566
5790
|
let entries;
|
|
5567
5791
|
try {
|
|
5568
|
-
entries = (0,
|
|
5792
|
+
entries = (0, import_node_fs15.readdirSync)(directory, { withFileTypes: true });
|
|
5569
5793
|
} catch {
|
|
5570
5794
|
return;
|
|
5571
5795
|
}
|
|
5572
5796
|
for (const entry2 of entries) {
|
|
5573
5797
|
if (paths.length >= 64) return;
|
|
5574
|
-
const path2 = (0,
|
|
5798
|
+
const path2 = (0, import_node_path17.join)(directory, entry2.name);
|
|
5575
5799
|
if (entry2.name === "energy_uj") {
|
|
5576
5800
|
paths.push(path2);
|
|
5577
5801
|
continue;
|
|
@@ -5615,8 +5839,8 @@ function errorText2(error2) {
|
|
|
5615
5839
|
}
|
|
5616
5840
|
|
|
5617
5841
|
// src/operations/recovery.ts
|
|
5618
|
-
var
|
|
5619
|
-
var
|
|
5842
|
+
var import_node_fs16 = require("node:fs");
|
|
5843
|
+
var import_node_path18 = require("node:path");
|
|
5620
5844
|
var import_node_sqlite3 = require("node:sqlite");
|
|
5621
5845
|
var MAX_AUDIT_EVENTS = 1e3;
|
|
5622
5846
|
var AUDIT_ACTOR = "local-recovery";
|
|
@@ -5631,13 +5855,13 @@ async function recoverAdminPassword(options) {
|
|
|
5631
5855
|
if (typeof options.password !== "string" || options.password.length === 0 || options.password.length > MAX_BROWSER_PASSWORD_CHARS) {
|
|
5632
5856
|
throw new OperationsError("invalid-password", `password must be 1..${MAX_BROWSER_PASSWORD_CHARS} characters`);
|
|
5633
5857
|
}
|
|
5634
|
-
if (!(0,
|
|
5858
|
+
if (!(0, import_node_fs16.existsSync)(database)) {
|
|
5635
5859
|
throw new OperationsError("missing-database", `hub database does not exist: ${database}`);
|
|
5636
5860
|
}
|
|
5637
5861
|
assertPrivateRegularFile(database, "database");
|
|
5638
|
-
const ownLock = (0,
|
|
5862
|
+
const ownLock = (0, import_node_path18.resolve)(`${database}.hub.lock`);
|
|
5639
5863
|
const otherLock = findHubLock(database);
|
|
5640
|
-
if (otherLock !== null && (0,
|
|
5864
|
+
if (otherLock !== null && (0, import_node_path18.resolve)(otherLock) !== ownLock) {
|
|
5641
5865
|
throw new OperationsError(
|
|
5642
5866
|
"hub-active",
|
|
5643
5867
|
`a hub lock exists at ${otherLock}; stop the hub and inspect that lock before recovery`
|
|
@@ -5735,10 +5959,10 @@ async function recoverAdminPassword(options) {
|
|
|
5735
5959
|
}
|
|
5736
5960
|
|
|
5737
5961
|
// src/cli/system.ts
|
|
5738
|
-
var
|
|
5962
|
+
var import_node_fs17 = require("node:fs");
|
|
5739
5963
|
var import_node_child_process5 = require("node:child_process");
|
|
5740
|
-
var
|
|
5741
|
-
var
|
|
5964
|
+
var import_node_crypto12 = require("node:crypto");
|
|
5965
|
+
var import_node_path19 = require("node:path");
|
|
5742
5966
|
var import_node_sqlite4 = require("node:sqlite");
|
|
5743
5967
|
var import_node_util = require("node:util");
|
|
5744
5968
|
var SYSTEM_SCOPE = "system";
|
|
@@ -5848,24 +6072,24 @@ function createSystemHost(overrides = {}) {
|
|
|
5848
6072
|
}
|
|
5849
6073
|
function defaultSystemPaths(overrides = {}) {
|
|
5850
6074
|
return {
|
|
5851
|
-
prefix: (0,
|
|
5852
|
-
configDir: (0,
|
|
5853
|
-
stateDir: (0,
|
|
5854
|
-
unitsDir: (0,
|
|
5855
|
-
sysusersDir: (0,
|
|
5856
|
-
udevRulesDir: (0,
|
|
5857
|
-
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")
|
|
5858
6082
|
};
|
|
5859
6083
|
}
|
|
5860
6084
|
function unitNamesForComponents(components) {
|
|
5861
6085
|
return COMPONENTS3.filter((component) => componentSet(components)[component]).map(unitFor);
|
|
5862
6086
|
}
|
|
5863
6087
|
function isWithin(parent, candidate) {
|
|
5864
|
-
const rel = (0,
|
|
5865
|
-
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);
|
|
5866
6090
|
}
|
|
5867
6091
|
function ensureAbsolute(path2, label3) {
|
|
5868
|
-
const absolute = (0,
|
|
6092
|
+
const absolute = (0, import_node_path19.resolve)(path2);
|
|
5869
6093
|
if (/[\0\r\n]/.test(absolute)) throw new SystemError("unsafe-path", `${label3} contains control characters`);
|
|
5870
6094
|
if (absolute === "/") throw new SystemError("unsafe-path", `${label3} must not be the filesystem root`);
|
|
5871
6095
|
for (const forbidden of ["/home", "/root", "/proc", "/sys", "/dev", "/boot"]) {
|
|
@@ -5879,7 +6103,7 @@ function validateSystemPaths(input = {}) {
|
|
|
5879
6103
|
const paths = defaultSystemPaths(input);
|
|
5880
6104
|
for (const [label3, value] of Object.entries(paths)) {
|
|
5881
6105
|
if (label3 === "powercapRoot") {
|
|
5882
|
-
if (!(0,
|
|
6106
|
+
if (!(0, import_node_path19.isAbsolute)(value) || /[\0\r\n]/.test(value) || (0, import_node_path19.resolve)(value) === "/") {
|
|
5883
6107
|
throw new SystemError("unsafe-path", `powercap root is unsafe: ${value}`);
|
|
5884
6108
|
}
|
|
5885
6109
|
} else {
|
|
@@ -5935,18 +6159,18 @@ function runMaybe(host, command, args, options) {
|
|
|
5935
6159
|
return host.run(command, args, options);
|
|
5936
6160
|
}
|
|
5937
6161
|
function sha256File2(path2) {
|
|
5938
|
-
return (0,
|
|
6162
|
+
return (0, import_node_crypto12.createHash)("sha256").update((0, import_node_fs17.readFileSync)(path2)).digest("hex");
|
|
5939
6163
|
}
|
|
5940
6164
|
function atomicWrite(path2, content, mode) {
|
|
5941
|
-
(0,
|
|
5942
|
-
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)}`);
|
|
5943
6167
|
try {
|
|
5944
|
-
(0,
|
|
5945
|
-
(0,
|
|
5946
|
-
(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);
|
|
5947
6171
|
} catch (error2) {
|
|
5948
6172
|
try {
|
|
5949
|
-
(0,
|
|
6173
|
+
(0, import_node_fs17.unlinkSync)(temporary);
|
|
5950
6174
|
} catch {
|
|
5951
6175
|
}
|
|
5952
6176
|
throw error2;
|
|
@@ -5955,12 +6179,12 @@ function atomicWrite(path2, content, mode) {
|
|
|
5955
6179
|
function ensureDirectory(path2, mode, privateDirectory2 = false) {
|
|
5956
6180
|
let stat;
|
|
5957
6181
|
try {
|
|
5958
|
-
stat = (0,
|
|
6182
|
+
stat = (0, import_node_fs17.lstatSync)(path2);
|
|
5959
6183
|
} catch (error2) {
|
|
5960
6184
|
if (error2.code !== "ENOENT") throw error2;
|
|
5961
|
-
(0,
|
|
5962
|
-
(0,
|
|
5963
|
-
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);
|
|
5964
6188
|
}
|
|
5965
6189
|
if (!stat.isDirectory() || stat.isSymbolicLink()) {
|
|
5966
6190
|
throw new SystemError("unsafe-path", `${path2} must be a real directory`);
|
|
@@ -5975,8 +6199,8 @@ function isDefaultSystemLayout(paths) {
|
|
|
5975
6199
|
}
|
|
5976
6200
|
function assertManagedPathSafety(paths, enforceRoot) {
|
|
5977
6201
|
for (const path2 of [paths.prefix, paths.configDir, paths.stateDir, paths.unitsDir, paths.sysusersDir, paths.udevRulesDir]) {
|
|
5978
|
-
if (!(0,
|
|
5979
|
-
const stat = (0,
|
|
6202
|
+
if (!(0, import_node_fs17.existsSync)(path2)) continue;
|
|
6203
|
+
const stat = (0, import_node_fs17.lstatSync)(path2);
|
|
5980
6204
|
if (!stat.isDirectory() || stat.isSymbolicLink()) {
|
|
5981
6205
|
throw new SystemError("unsafe-path", `${path2} must be a real directory`);
|
|
5982
6206
|
}
|
|
@@ -5989,8 +6213,8 @@ function assertManagedPathSafety(paths, enforceRoot) {
|
|
|
5989
6213
|
}
|
|
5990
6214
|
}
|
|
5991
6215
|
function writeManagedFile(path2, content, mode, replace) {
|
|
5992
|
-
if ((0,
|
|
5993
|
-
const stat = (0,
|
|
6216
|
+
if ((0, import_node_fs17.existsSync)(path2)) {
|
|
6217
|
+
const stat = (0, import_node_fs17.lstatSync)(path2);
|
|
5994
6218
|
if (!stat.isFile() || stat.isSymbolicLink()) {
|
|
5995
6219
|
throw new SystemError("unsafe-path", `${path2} must be a regular file, not a symlink`);
|
|
5996
6220
|
}
|
|
@@ -6029,7 +6253,7 @@ function parseEnvValue(value) {
|
|
|
6029
6253
|
function readEnvDocument(path2) {
|
|
6030
6254
|
let raw;
|
|
6031
6255
|
try {
|
|
6032
|
-
raw = (0,
|
|
6256
|
+
raw = (0, import_node_fs17.readFileSync)(path2, "utf8");
|
|
6033
6257
|
} catch (error2) {
|
|
6034
6258
|
if (error2.code === "ENOENT") return null;
|
|
6035
6259
|
throw error2;
|
|
@@ -6076,43 +6300,43 @@ function connectDestinationUrl(value) {
|
|
|
6076
6300
|
return url.href;
|
|
6077
6301
|
}
|
|
6078
6302
|
function hubDatabasePath(paths) {
|
|
6079
|
-
return (0,
|
|
6303
|
+
return (0, import_node_path19.join)(paths.stateDir, "hub", "telemetry.sqlite");
|
|
6080
6304
|
}
|
|
6081
6305
|
function hubEnrollmentPath(paths) {
|
|
6082
|
-
return (0,
|
|
6306
|
+
return (0, import_node_path19.join)(paths.stateDir, "hub", "enrollment.json");
|
|
6083
6307
|
}
|
|
6084
6308
|
function hubSocketPath(paths) {
|
|
6085
|
-
return (0,
|
|
6309
|
+
return (0, import_node_path19.join)(paths.stateDir, "hub", "run", "hub.sock");
|
|
6086
6310
|
}
|
|
6087
6311
|
function collectorStatePath2(paths) {
|
|
6088
|
-
return (0,
|
|
6312
|
+
return (0, import_node_path19.join)(paths.stateDir, "collector", "state.json");
|
|
6089
6313
|
}
|
|
6090
6314
|
function hubEnvPath(paths) {
|
|
6091
|
-
return (0,
|
|
6315
|
+
return (0, import_node_path19.join)(paths.configDir, "hub.env");
|
|
6092
6316
|
}
|
|
6093
6317
|
function collectorEnvPath(paths) {
|
|
6094
|
-
return (0,
|
|
6318
|
+
return (0, import_node_path19.join)(paths.configDir, "collector.env");
|
|
6095
6319
|
}
|
|
6096
6320
|
function sysusersPath(paths) {
|
|
6097
|
-
return (0,
|
|
6321
|
+
return (0, import_node_path19.join)(paths.sysusersDir, SYSUSERS_NAME);
|
|
6098
6322
|
}
|
|
6099
6323
|
function powerSysusersPath(paths) {
|
|
6100
|
-
return (0,
|
|
6324
|
+
return (0, import_node_path19.join)(paths.sysusersDir, POWER_SYSUSERS_NAME);
|
|
6101
6325
|
}
|
|
6102
6326
|
function raplRulePath(paths) {
|
|
6103
|
-
return (0,
|
|
6327
|
+
return (0, import_node_path19.join)(paths.udevRulesDir, RAPL_RULE_NAME);
|
|
6104
6328
|
}
|
|
6105
6329
|
function stateFilePath(paths) {
|
|
6106
|
-
return (0,
|
|
6330
|
+
return (0, import_node_path19.join)(paths.stateDir, STATE_FILE_NAME);
|
|
6107
6331
|
}
|
|
6108
6332
|
function readCollectorIdentity(path2) {
|
|
6109
|
-
if (!(0,
|
|
6110
|
-
const stat = (0,
|
|
6333
|
+
if (!(0, import_node_fs17.existsSync)(path2)) return null;
|
|
6334
|
+
const stat = (0, import_node_fs17.lstatSync)(path2);
|
|
6111
6335
|
if (!stat.isFile() || stat.isSymbolicLink()) throw new SystemError("unsafe-path", `${path2} must be a regular file`);
|
|
6112
6336
|
if ((stat.mode & 63) !== 0) throw new SystemError("insecure-permissions", `${path2} must be private (0600)`);
|
|
6113
6337
|
let raw;
|
|
6114
6338
|
try {
|
|
6115
|
-
raw = JSON.parse((0,
|
|
6339
|
+
raw = JSON.parse((0, import_node_fs17.readFileSync)(path2, "utf8"));
|
|
6116
6340
|
} catch {
|
|
6117
6341
|
throw new SystemError("invalid-file", `${path2} is not valid JSON`);
|
|
6118
6342
|
}
|
|
@@ -6146,7 +6370,7 @@ function readCollectorIdentity(path2) {
|
|
|
6146
6370
|
return { collectorId: record.collectorId, destinations };
|
|
6147
6371
|
}
|
|
6148
6372
|
function writeCollectorIdentity(path2, identity) {
|
|
6149
|
-
ensureDirectory((0,
|
|
6373
|
+
ensureDirectory((0, import_node_path19.dirname)(path2), 448, true);
|
|
6150
6374
|
atomicWrite(path2, `${JSON.stringify(identity)}
|
|
6151
6375
|
`, 384);
|
|
6152
6376
|
}
|
|
@@ -6186,7 +6410,7 @@ function ensureHubOwner(paths) {
|
|
|
6186
6410
|
if (!Array.isArray(parsed)) throw new SystemError("invalid-config", "HUB_BROWSER_USERS must be a JSON array");
|
|
6187
6411
|
if (parsed.length > 0) return void 0;
|
|
6188
6412
|
}
|
|
6189
|
-
const password = (0,
|
|
6413
|
+
const password = (0, import_node_crypto12.randomBytes)(18).toString("base64url");
|
|
6190
6414
|
const users = [{ username: "owner", passwordHash: hashPassword(password), machineIds: "*", admin: true }];
|
|
6191
6415
|
writeEnvValue(hubEnvPath(paths), "HUB_BROWSER_USERS", JSON.stringify(users));
|
|
6192
6416
|
return password;
|
|
@@ -6237,7 +6461,7 @@ function updateHubCollectorRegistry(paths, identity) {
|
|
|
6237
6461
|
}
|
|
6238
6462
|
function registerCollectorInHubDatabase(paths, identity, host) {
|
|
6239
6463
|
const database = hubDatabasePath(paths);
|
|
6240
|
-
if (!(0,
|
|
6464
|
+
if (!(0, import_node_fs17.existsSync)(database)) return { inserted: false };
|
|
6241
6465
|
const db = new import_node_sqlite4.DatabaseSync(database, { timeout: 5e3 });
|
|
6242
6466
|
try {
|
|
6243
6467
|
const table = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='collector_registry'").get();
|
|
@@ -6252,7 +6476,7 @@ function registerCollectorInHubDatabase(paths, identity, host) {
|
|
|
6252
6476
|
}
|
|
6253
6477
|
function findCollectorInHubDatabase(paths, collectorId) {
|
|
6254
6478
|
const database = hubDatabasePath(paths);
|
|
6255
|
-
if (!(0,
|
|
6479
|
+
if (!(0, import_node_fs17.existsSync)(database)) return null;
|
|
6256
6480
|
const db = new import_node_sqlite4.DatabaseSync(database, { readOnly: true, timeout: 5e3 });
|
|
6257
6481
|
try {
|
|
6258
6482
|
const table = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='collector_registry'").get();
|
|
@@ -6265,9 +6489,9 @@ function findCollectorInHubDatabase(paths, collectorId) {
|
|
|
6265
6489
|
}
|
|
6266
6490
|
function createLocalEnrollmentGrant(paths, host) {
|
|
6267
6491
|
const database = hubDatabasePath(paths);
|
|
6268
|
-
if (!(0,
|
|
6269
|
-
const token = (0,
|
|
6270
|
-
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");
|
|
6271
6495
|
const expiresAt = host.now() + 10 * 60 * 1e3;
|
|
6272
6496
|
const db = new import_node_sqlite4.DatabaseSync(database, { timeout: 5e3 });
|
|
6273
6497
|
try {
|
|
@@ -6319,7 +6543,7 @@ async function pairCollectorWithHub(options) {
|
|
|
6319
6543
|
note: "the local hub has no reachable loopback or HTTPS destination"
|
|
6320
6544
|
};
|
|
6321
6545
|
}
|
|
6322
|
-
if (!(0,
|
|
6546
|
+
if (!(0, import_node_fs17.existsSync)((0, import_node_path19.join)(paths.unitsDir, UNIT_NAMES.hub))) {
|
|
6323
6547
|
return { paired: false, awaiting: true, hubWasActive: false, note: "the local hub unit is not installed" };
|
|
6324
6548
|
}
|
|
6325
6549
|
const hubWasActive = systemdActive(host, UNIT_NAMES.hub);
|
|
@@ -6332,7 +6556,7 @@ async function pairCollectorWithHub(options) {
|
|
|
6332
6556
|
destinations: [{ url: destination.url, token: registered.token, sharing: { ...SYSTEM_DEFAULT_SHARING } }]
|
|
6333
6557
|
};
|
|
6334
6558
|
writeCollectorIdentity(collectorStatePath2(paths), adopted);
|
|
6335
|
-
chownAccount([(0,
|
|
6559
|
+
chownAccount([(0, import_node_path19.join)(paths.stateDir, "collector")], accounts.collector, accounts.collector, host);
|
|
6336
6560
|
return { paired: true, awaiting: false, hubWasActive, destination: destination.url };
|
|
6337
6561
|
}
|
|
6338
6562
|
}
|
|
@@ -6340,7 +6564,7 @@ async function pairCollectorWithHub(options) {
|
|
|
6340
6564
|
try {
|
|
6341
6565
|
grant = createLocalEnrollmentGrant(paths, host);
|
|
6342
6566
|
} catch (error2) {
|
|
6343
|
-
chownAccount([(0,
|
|
6567
|
+
chownAccount([(0, import_node_path19.join)(paths.stateDir, "collector")], accounts.collector, accounts.collector, host);
|
|
6344
6568
|
return {
|
|
6345
6569
|
paired: false,
|
|
6346
6570
|
awaiting: true,
|
|
@@ -6358,18 +6582,18 @@ async function pairCollectorWithHub(options) {
|
|
|
6358
6582
|
note: `enrollment through the live hub failed: ${error2 instanceof Error ? error2.message : String(error2)}`
|
|
6359
6583
|
};
|
|
6360
6584
|
} finally {
|
|
6361
|
-
chownAccount([(0,
|
|
6585
|
+
chownAccount([(0, import_node_path19.join)(paths.stateDir, "collector")], accounts.collector, accounts.collector, host);
|
|
6362
6586
|
}
|
|
6363
6587
|
if (!collectorConfigured(paths).configured) {
|
|
6364
6588
|
return { paired: false, awaiting: true, hubWasActive, note: "the hub accepted enrollment but no destination was saved" };
|
|
6365
6589
|
}
|
|
6366
|
-
chownAccount([(0,
|
|
6590
|
+
chownAccount([(0, import_node_path19.join)(paths.stateDir, "collector")], accounts.collector, accounts.collector, host);
|
|
6367
6591
|
return { paired: true, awaiting: false, hubWasActive, destination: destination.url };
|
|
6368
6592
|
}
|
|
6369
6593
|
const identity = {
|
|
6370
|
-
collectorId: existing?.collectorId ?? (0,
|
|
6371
|
-
machineId: (0,
|
|
6372
|
-
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")
|
|
6373
6597
|
};
|
|
6374
6598
|
const registry = registerCollectorInHubDatabase(paths, identity, host);
|
|
6375
6599
|
let token = identity.token;
|
|
@@ -6396,7 +6620,7 @@ async function pairCollectorWithHub(options) {
|
|
|
6396
6620
|
}
|
|
6397
6621
|
];
|
|
6398
6622
|
writeCollectorIdentity(collectorStatePath2(paths), next);
|
|
6399
|
-
chownAccount([(0,
|
|
6623
|
+
chownAccount([(0, import_node_path19.join)(paths.stateDir, "collector")], accounts.collector, accounts.collector, host);
|
|
6400
6624
|
return { paired: true, awaiting: false, hubWasActive, destination: destination.url };
|
|
6401
6625
|
}
|
|
6402
6626
|
function unitCommon(name, description, paths, account, envPath, execStart, extraService = []) {
|
|
@@ -6413,7 +6637,7 @@ function unitCommon(name, description, paths, account, envPath, execStart, extra
|
|
|
6413
6637
|
"Type=simple",
|
|
6414
6638
|
`User=${account}`,
|
|
6415
6639
|
`Group=${account}`,
|
|
6416
|
-
`WorkingDirectory=${(0,
|
|
6640
|
+
`WorkingDirectory=${(0, import_node_path19.join)(paths.prefix, "current").replace(/%/g, "%%")}`,
|
|
6417
6641
|
`EnvironmentFile=${envPath.replace(/%/g, "%%")}`,
|
|
6418
6642
|
"Environment=NODE_ENV=production",
|
|
6419
6643
|
"Restart=on-failure",
|
|
@@ -6448,13 +6672,13 @@ function unitCommon(name, description, paths, account, envPath, execStart, extra
|
|
|
6448
6672
|
}
|
|
6449
6673
|
function renderSystemHubUnit(options) {
|
|
6450
6674
|
const { paths, accounts } = options;
|
|
6451
|
-
const hubScript = (0,
|
|
6675
|
+
const hubScript = (0, import_node_path19.join)(paths.prefix, "current", "dist", "hub.cjs");
|
|
6452
6676
|
const extra = [
|
|
6453
6677
|
`Environment=${systemdQuote(`HUB_DATABASE_PATH=${options.database}`)}`,
|
|
6454
6678
|
`Environment=${systemdQuote(`HUB_STATE_FILE=${options.enrollment}`)}`,
|
|
6455
6679
|
...options.remote ? [`Environment=${systemdQuote(`HUB_SOCKET_PATH=${options.socket}`)}`] : [],
|
|
6456
|
-
`ReadWritePaths=${systemdQuote((0,
|
|
6457
|
-
`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"))}`,
|
|
6458
6682
|
"PrivateDevices=yes",
|
|
6459
6683
|
"TimeoutStopSec=15s"
|
|
6460
6684
|
];
|
|
@@ -6473,14 +6697,14 @@ function renderSystemHubUnit(options) {
|
|
|
6473
6697
|
}
|
|
6474
6698
|
function renderSystemCollectorUnit(options) {
|
|
6475
6699
|
const { paths, accounts } = options;
|
|
6476
|
-
const collectorScript = (0,
|
|
6700
|
+
const collectorScript = (0, import_node_path19.join)(paths.prefix, "current", "dist", "collector.cjs");
|
|
6477
6701
|
const extra = [
|
|
6478
6702
|
...options.powerAccess ? [`SupplementaryGroups=${accounts.powerGroup}`] : [],
|
|
6479
6703
|
`Environment=${systemdQuote(`COLLECTOR_MODE=real`)}`,
|
|
6480
6704
|
`Environment=${systemdQuote(`COLLECTOR_STATE_FILE=${options.collectorState}`)}`,
|
|
6481
|
-
`Environment=${systemdQuote(`COLLECTOR_HEALTH_FILE=${(0,
|
|
6482
|
-
`ReadWritePaths=${systemdQuote((0,
|
|
6483
|
-
`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"))}`,
|
|
6484
6708
|
"TimeoutStopSec=10s"
|
|
6485
6709
|
];
|
|
6486
6710
|
return [
|
|
@@ -6553,11 +6777,15 @@ function collectorEnvTemplate() {
|
|
|
6553
6777
|
"# COLLECTOR_ENROLL_URL=ws://127.0.0.1:8081/api/collector/connect",
|
|
6554
6778
|
"# COLLECTOR_ENROLL_TOKEN=<one-use grant>",
|
|
6555
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",
|
|
6556
6784
|
""
|
|
6557
6785
|
].join("\n");
|
|
6558
6786
|
}
|
|
6559
6787
|
function assertPrivateSourceFile(path2, label3) {
|
|
6560
|
-
const stat = (0,
|
|
6788
|
+
const stat = (0, import_node_fs17.lstatSync)(path2);
|
|
6561
6789
|
if (!stat.isFile() || stat.isSymbolicLink()) {
|
|
6562
6790
|
throw new SystemError("unsafe-adoption", `${label3} must be a regular file: ${path2}`);
|
|
6563
6791
|
}
|
|
@@ -6568,7 +6796,7 @@ function assertPrivateSourceFile(path2, label3) {
|
|
|
6568
6796
|
function readJsonObject(path2) {
|
|
6569
6797
|
let raw;
|
|
6570
6798
|
try {
|
|
6571
|
-
raw = (0,
|
|
6799
|
+
raw = (0, import_node_fs17.readFileSync)(path2, "utf8");
|
|
6572
6800
|
} catch (error2) {
|
|
6573
6801
|
throw new SystemError("missing-file", `cannot read ${path2}: ${error2.message}`);
|
|
6574
6802
|
}
|
|
@@ -6591,8 +6819,8 @@ function isCanonicalComponents(value) {
|
|
|
6591
6819
|
}
|
|
6592
6820
|
function readSystemState(paths) {
|
|
6593
6821
|
const path2 = stateFilePath(paths);
|
|
6594
|
-
if (!(0,
|
|
6595
|
-
const stat = (0,
|
|
6822
|
+
if (!(0, import_node_fs17.existsSync)(path2)) return null;
|
|
6823
|
+
const stat = (0, import_node_fs17.lstatSync)(path2);
|
|
6596
6824
|
if (!stat.isFile() || stat.isSymbolicLink()) throw new SystemError("unsafe-path", `${path2} must be a regular file`);
|
|
6597
6825
|
if ((stat.mode & 63) !== 0) throw new SystemError("insecure-permissions", `${path2} must be 0600`);
|
|
6598
6826
|
const raw = readJsonObject(path2);
|
|
@@ -6624,7 +6852,7 @@ function readSystemState(paths) {
|
|
|
6624
6852
|
}
|
|
6625
6853
|
function systemStateIsLegacy(paths) {
|
|
6626
6854
|
const path2 = stateFilePath(paths);
|
|
6627
|
-
if (!(0,
|
|
6855
|
+
if (!(0, import_node_fs17.existsSync)(path2)) return false;
|
|
6628
6856
|
let raw;
|
|
6629
6857
|
try {
|
|
6630
6858
|
raw = readJsonObject(path2);
|
|
@@ -6675,24 +6903,24 @@ function validateVersion2(value) {
|
|
|
6675
6903
|
return value;
|
|
6676
6904
|
}
|
|
6677
6905
|
function releaseVersion(root) {
|
|
6678
|
-
const metadata = readJsonObject((0,
|
|
6906
|
+
const metadata = readJsonObject((0, import_node_path19.join)(root, "package.json"));
|
|
6679
6907
|
if (Object.hasOwn(metadata, "rigscopeConfigVersion")) {
|
|
6680
6908
|
throw new SystemError("invalid-release", "release uses unfinished configuration metadata; select a canonical release");
|
|
6681
6909
|
}
|
|
6682
6910
|
return validateVersion2(metadata.version);
|
|
6683
6911
|
}
|
|
6684
6912
|
function releaseSchemaVersion(root) {
|
|
6685
|
-
const manifestPath = (0,
|
|
6686
|
-
if (!(0,
|
|
6913
|
+
const manifestPath = (0, import_node_path19.join)(root, "manifest.json");
|
|
6914
|
+
if (!(0, import_node_fs17.existsSync)(manifestPath)) return null;
|
|
6687
6915
|
const manifest = readJsonObject(manifestPath);
|
|
6688
6916
|
return Number.isSafeInteger(manifest.schemaVersion) ? Number(manifest.schemaVersion) : null;
|
|
6689
6917
|
}
|
|
6690
6918
|
function assertReleaseArtifacts(root) {
|
|
6691
6919
|
for (const artifact of REQUIRED_ARTIFACTS) {
|
|
6692
|
-
const path2 = (0,
|
|
6920
|
+
const path2 = (0, import_node_path19.join)(root, artifact);
|
|
6693
6921
|
let stat;
|
|
6694
6922
|
try {
|
|
6695
|
-
stat = (0,
|
|
6923
|
+
stat = (0, import_node_fs17.lstatSync)(path2);
|
|
6696
6924
|
} catch {
|
|
6697
6925
|
throw new SystemError("missing-artifact", `release is missing ${artifact}`);
|
|
6698
6926
|
}
|
|
@@ -6700,12 +6928,12 @@ function assertReleaseArtifacts(root) {
|
|
|
6700
6928
|
throw new SystemError("invalid-artifact", `release artifact is not a non-empty regular file: ${artifact}`);
|
|
6701
6929
|
}
|
|
6702
6930
|
}
|
|
6703
|
-
const buildId = (0,
|
|
6931
|
+
const buildId = (0, import_node_fs17.readFileSync)((0, import_node_path19.join)(root, ".next", "BUILD_ID"), "utf8").trim();
|
|
6704
6932
|
if (buildId === "" || /\s/.test(buildId)) throw new SystemError("invalid-artifact", ".next/BUILD_ID is invalid");
|
|
6705
6933
|
for (const directory of [".next/server", ".next/static"]) {
|
|
6706
6934
|
let stat;
|
|
6707
6935
|
try {
|
|
6708
|
-
stat = (0,
|
|
6936
|
+
stat = (0, import_node_fs17.lstatSync)((0, import_node_path19.join)(root, directory));
|
|
6709
6937
|
} catch {
|
|
6710
6938
|
throw new SystemError("missing-artifact", `release is missing ${directory}/`);
|
|
6711
6939
|
}
|
|
@@ -6713,10 +6941,10 @@ function assertReleaseArtifacts(root) {
|
|
|
6713
6941
|
}
|
|
6714
6942
|
}
|
|
6715
6943
|
function verifyReleaseManifest(root) {
|
|
6716
|
-
const manifestPath = (0,
|
|
6717
|
-
if (!(0,
|
|
6944
|
+
const manifestPath = (0, import_node_path19.join)(root, "manifest.json");
|
|
6945
|
+
if (!(0, import_node_fs17.existsSync)(manifestPath)) return;
|
|
6718
6946
|
const manifest = readJsonObject(manifestPath);
|
|
6719
|
-
const packageJson = readJsonObject((0,
|
|
6947
|
+
const packageJson = readJsonObject((0, import_node_path19.join)(root, "package.json"));
|
|
6720
6948
|
if (manifest.name !== void 0 && manifest.name !== packageJson.name) {
|
|
6721
6949
|
throw new SystemError("manifest-mismatch", "release manifest name does not match package.json");
|
|
6722
6950
|
}
|
|
@@ -6735,17 +6963,17 @@ function verifyReleaseManifest(root) {
|
|
|
6735
6963
|
if (typeof relativePath !== "string" || relativePath === "" || relativePath.startsWith("/") || relativePath.includes("\\") || relativePath.split("/").includes("..")) {
|
|
6736
6964
|
throw new SystemError("invalid-manifest", `release manifest contains an unsafe path: ${String(relativePath)}`);
|
|
6737
6965
|
}
|
|
6738
|
-
const absolute = (0,
|
|
6739
|
-
const stat = (0,
|
|
6966
|
+
const absolute = (0, import_node_path19.join)(root, relativePath);
|
|
6967
|
+
const stat = (0, import_node_fs17.lstatSync)(absolute);
|
|
6740
6968
|
if (!stat.isFile() || stat.isSymbolicLink()) throw new SystemError("invalid-manifest", `release artifact is not a regular file: ${relativePath}`);
|
|
6741
6969
|
if (entry2.bytes !== stat.size) throw new SystemError("artifact-mismatch", `release artifact size changed: ${relativePath}`);
|
|
6742
6970
|
if (entry2.sha256 !== sha256File2(absolute)) throw new SystemError("artifact-mismatch", `release artifact hash changed: ${relativePath}`);
|
|
6743
6971
|
listed.add(relativePath);
|
|
6744
6972
|
}
|
|
6745
6973
|
const visit = (current) => {
|
|
6746
|
-
for (const entry2 of (0,
|
|
6747
|
-
const absolute = (0,
|
|
6748
|
-
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("/");
|
|
6749
6977
|
if (rel === "node_modules" || rel.startsWith("node_modules/") || rel === ".next/cache" || rel.startsWith(".next/cache/")) continue;
|
|
6750
6978
|
if (entry2.isSymbolicLink()) throw new SystemError("unsafe-release", `release contains a symlink: ${rel}`);
|
|
6751
6979
|
if (entry2.isDirectory()) {
|
|
@@ -6760,49 +6988,49 @@ function verifyReleaseManifest(root) {
|
|
|
6760
6988
|
}
|
|
6761
6989
|
function assertNoSymlinks(root) {
|
|
6762
6990
|
const visit = (path2) => {
|
|
6763
|
-
const stat = (0,
|
|
6764
|
-
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)}`);
|
|
6765
6993
|
if (!stat.isDirectory()) return;
|
|
6766
|
-
for (const entry2 of (0,
|
|
6994
|
+
for (const entry2 of (0, import_node_fs17.readdirSync)(path2)) visit((0, import_node_path19.join)(path2, entry2));
|
|
6767
6995
|
};
|
|
6768
6996
|
visit(root);
|
|
6769
6997
|
}
|
|
6770
6998
|
function copyReleaseTree(source, destination) {
|
|
6771
6999
|
const visit = (current, target) => {
|
|
6772
|
-
const stat = (0,
|
|
6773
|
-
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)}`);
|
|
6774
7002
|
if (stat.isDirectory()) {
|
|
6775
|
-
(0,
|
|
6776
|
-
for (const entry2 of (0,
|
|
6777
|
-
const child = (0,
|
|
6778
|
-
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);
|
|
6779
7007
|
if (rel === ".git" || rel === ".next-dev" || rel === ".next/cache" || rel === "node_modules" || rel.startsWith("node_modules/")) {
|
|
6780
7008
|
continue;
|
|
6781
7009
|
}
|
|
6782
|
-
visit(child, (0,
|
|
7010
|
+
visit(child, (0, import_node_path19.join)(target, entry2));
|
|
6783
7011
|
}
|
|
6784
7012
|
return;
|
|
6785
7013
|
}
|
|
6786
|
-
if (!stat.isFile()) throw new SystemError("unsafe-release", `source contains a non-regular file: ${(0,
|
|
6787
|
-
(0,
|
|
6788
|
-
(0,
|
|
6789
|
-
(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);
|
|
6790
7018
|
};
|
|
6791
7019
|
visit(source, destination);
|
|
6792
7020
|
}
|
|
6793
7021
|
function copyReleaseAllowlisted(source, destination) {
|
|
6794
|
-
for (const entry2 of (0,
|
|
7022
|
+
for (const entry2 of (0, import_node_fs17.readdirSync)(source)) {
|
|
6795
7023
|
if (!PACKAGE_TOP_LEVEL.has(entry2)) continue;
|
|
6796
7024
|
if (entry2 === "node_modules") continue;
|
|
6797
|
-
const child = (0,
|
|
6798
|
-
const target = (0,
|
|
6799
|
-
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);
|
|
6800
7028
|
if (stat.isSymbolicLink()) throw new SystemError("unsafe-release", `source contains a symlink: ${entry2}`);
|
|
6801
7029
|
if (stat.isDirectory()) {
|
|
6802
7030
|
copyReleaseTree(child, target);
|
|
6803
7031
|
} else if (stat.isFile()) {
|
|
6804
|
-
(0,
|
|
6805
|
-
(0,
|
|
7032
|
+
(0, import_node_fs17.copyFileSync)(child, target);
|
|
7033
|
+
(0, import_node_fs17.chmodSync)(target, 420);
|
|
6806
7034
|
}
|
|
6807
7035
|
}
|
|
6808
7036
|
}
|
|
@@ -6837,28 +7065,28 @@ function extractArchive(archive, stage, host) {
|
|
|
6837
7065
|
}
|
|
6838
7066
|
function discardStagedRelease(staged) {
|
|
6839
7067
|
if (staged === null) return;
|
|
6840
|
-
(0,
|
|
7068
|
+
(0, import_node_fs17.rmSync)(staged.stageDir, { recursive: true, force: true });
|
|
6841
7069
|
}
|
|
6842
7070
|
function releaseTargetDir(paths, version) {
|
|
6843
|
-
return (0,
|
|
7071
|
+
return (0, import_node_path19.join)(paths.prefix, "releases", version);
|
|
6844
7072
|
}
|
|
6845
7073
|
function assertReleaseTargetAvailable(paths, releaseDir, replaceRelease) {
|
|
6846
|
-
if (!(0,
|
|
7074
|
+
if (!(0, import_node_fs17.existsSync)(releaseDir)) return;
|
|
6847
7075
|
const current = currentReleaseDir(paths);
|
|
6848
7076
|
const previous = previousReleaseDir(paths);
|
|
6849
7077
|
if (!replaceRelease || current === releaseDir || previous === releaseDir) {
|
|
6850
7078
|
throw new SystemError(
|
|
6851
7079
|
"release-exists",
|
|
6852
|
-
`release ${(0,
|
|
7080
|
+
`release ${(0, import_node_path19.basename)(releaseDir)} is already installed${current === releaseDir || previous === releaseDir ? " or retained" : ""}; choose a new version`
|
|
6853
7081
|
);
|
|
6854
7082
|
}
|
|
6855
7083
|
}
|
|
6856
7084
|
function stageRelease(options) {
|
|
6857
|
-
const source = (0,
|
|
6858
|
-
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);
|
|
6859
7087
|
ensureDirectory(options.paths.prefix, 493);
|
|
6860
|
-
const stageDir = (0,
|
|
6861
|
-
(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 });
|
|
6862
7090
|
try {
|
|
6863
7091
|
if (stat.isDirectory() && !stat.isSymbolicLink()) {
|
|
6864
7092
|
copyReleaseAllowlisted(source, stageDir);
|
|
@@ -6876,7 +7104,7 @@ function stageRelease(options) {
|
|
|
6876
7104
|
artifacts: [...REQUIRED_ARTIFACTS]
|
|
6877
7105
|
};
|
|
6878
7106
|
} catch (error2) {
|
|
6879
|
-
(0,
|
|
7107
|
+
(0, import_node_fs17.rmSync)(stageDir, { recursive: true, force: true });
|
|
6880
7108
|
throw error2;
|
|
6881
7109
|
}
|
|
6882
7110
|
}
|
|
@@ -6902,13 +7130,13 @@ function prepareStagedRelease(options) {
|
|
|
6902
7130
|
}
|
|
6903
7131
|
}
|
|
6904
7132
|
function commitStagedRelease(options) {
|
|
6905
|
-
const releasesDir = (0,
|
|
7133
|
+
const releasesDir = (0, import_node_path19.join)(options.paths.prefix, "releases");
|
|
6906
7134
|
ensureDirectory(releasesDir, 493);
|
|
6907
7135
|
const releaseDir = releaseTargetDir(options.paths, options.staged.version);
|
|
6908
7136
|
assertReleaseTargetAvailable(options.paths, releaseDir, options.replaceRelease);
|
|
6909
|
-
if ((0,
|
|
6910
|
-
(0,
|
|
6911
|
-
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);
|
|
6912
7140
|
return {
|
|
6913
7141
|
version: options.staged.version,
|
|
6914
7142
|
releaseDir,
|
|
@@ -6917,20 +7145,20 @@ function commitStagedRelease(options) {
|
|
|
6917
7145
|
};
|
|
6918
7146
|
}
|
|
6919
7147
|
function dependencyNames(root) {
|
|
6920
|
-
const pkg = readJsonObject((0,
|
|
7148
|
+
const pkg = readJsonObject((0, import_node_path19.join)(root, "package.json"));
|
|
6921
7149
|
const dependencies2 = pkg.dependencies;
|
|
6922
7150
|
if (dependencies2 === null || typeof dependencies2 !== "object" || Array.isArray(dependencies2)) return [];
|
|
6923
7151
|
return Object.keys(dependencies2).filter((name) => /^[A-Za-z0-9@/._-]+$/.test(name));
|
|
6924
7152
|
}
|
|
6925
7153
|
function missingDependencies(root) {
|
|
6926
|
-
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")));
|
|
6927
7155
|
}
|
|
6928
7156
|
function installDependencies(root, host, command = "npm") {
|
|
6929
|
-
const hasLock = (0,
|
|
7157
|
+
const hasLock = (0, import_node_fs17.existsSync)((0, import_node_path19.join)(root, "package-lock.json"));
|
|
6930
7158
|
const args = hasLock ? ["ci", "--omit=dev", "--ignore-scripts", "--no-audit", "--no-fund"] : ["install", "--omit=dev", "--ignore-scripts", "--no-audit", "--no-fund"];
|
|
6931
|
-
const siblingNpm = (0,
|
|
6932
|
-
const executable = command === "npm" && (0,
|
|
6933
|
-
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);
|
|
6934
7162
|
const path2 = [nodeBin, process.env.PATH ?? ""].filter(Boolean).join(":");
|
|
6935
7163
|
runRequired(host, executable, args, "production dependency installation", {
|
|
6936
7164
|
cwd: root,
|
|
@@ -6939,21 +7167,21 @@ function installDependencies(root, host, command = "npm") {
|
|
|
6939
7167
|
});
|
|
6940
7168
|
}
|
|
6941
7169
|
function currentReleaseDir(paths) {
|
|
6942
|
-
const link = (0,
|
|
7170
|
+
const link = (0, import_node_path19.join)(paths.prefix, "current");
|
|
6943
7171
|
try {
|
|
6944
|
-
const target = (0,
|
|
6945
|
-
const absolute = (0,
|
|
6946
|
-
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;
|
|
6947
7175
|
} catch {
|
|
6948
7176
|
return null;
|
|
6949
7177
|
}
|
|
6950
7178
|
}
|
|
6951
7179
|
function previousReleaseDir(paths) {
|
|
6952
|
-
const link = (0,
|
|
7180
|
+
const link = (0, import_node_path19.join)(paths.prefix, "previous");
|
|
6953
7181
|
try {
|
|
6954
|
-
const target = (0,
|
|
6955
|
-
const absolute = (0,
|
|
6956
|
-
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;
|
|
6957
7185
|
} catch {
|
|
6958
7186
|
return null;
|
|
6959
7187
|
}
|
|
@@ -6961,11 +7189,11 @@ function previousReleaseDir(paths) {
|
|
|
6961
7189
|
function replaceSymlink(link, target, host) {
|
|
6962
7190
|
const temporary = `${link}.tmp-${process.pid}-${Date.now()}`;
|
|
6963
7191
|
try {
|
|
6964
|
-
(0,
|
|
6965
|
-
(0,
|
|
7192
|
+
(0, import_node_fs17.symlinkSync)(target, temporary);
|
|
7193
|
+
(0, import_node_fs17.renameSync)(temporary, link);
|
|
6966
7194
|
} catch (error2) {
|
|
6967
7195
|
try {
|
|
6968
|
-
(0,
|
|
7196
|
+
(0, import_node_fs17.unlinkSync)(temporary);
|
|
6969
7197
|
} catch {
|
|
6970
7198
|
}
|
|
6971
7199
|
throw error2;
|
|
@@ -6974,8 +7202,8 @@ function replaceSymlink(link, target, host) {
|
|
|
6974
7202
|
}
|
|
6975
7203
|
function removeSymlink(link) {
|
|
6976
7204
|
try {
|
|
6977
|
-
const stat = (0,
|
|
6978
|
-
if (stat.isSymbolicLink()) (0,
|
|
7205
|
+
const stat = (0, import_node_fs17.lstatSync)(link);
|
|
7206
|
+
if (stat.isSymbolicLink()) (0, import_node_fs17.unlinkSync)(link);
|
|
6979
7207
|
} catch {
|
|
6980
7208
|
}
|
|
6981
7209
|
}
|
|
@@ -6988,18 +7216,18 @@ function nodeVersion(host, nodePath) {
|
|
|
6988
7216
|
return output;
|
|
6989
7217
|
}
|
|
6990
7218
|
function ensureRootOwnedNode(options) {
|
|
6991
|
-
const selected = (0,
|
|
6992
|
-
const real = (0,
|
|
7219
|
+
const selected = (0, import_node_path19.resolve)(options.nodePath ?? process.execPath);
|
|
7220
|
+
const real = (0, import_node_fs17.realpathSync)(selected);
|
|
6993
7221
|
nodeVersion(options.host, real);
|
|
6994
|
-
const stat = (0,
|
|
6995
|
-
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);
|
|
6996
7224
|
const unsafe = stat.uid !== 0 || (stat.mode & 18) !== 0 || options.copyNode === true || insideRelease;
|
|
6997
7225
|
if (!unsafe || options.trustedNode === true) return real;
|
|
6998
|
-
const target = (0,
|
|
7226
|
+
const target = (0, import_node_path19.join)(options.paths.prefix, "node", "node");
|
|
6999
7227
|
if (!options.apply) return target;
|
|
7000
|
-
ensureDirectory((0,
|
|
7001
|
-
(0,
|
|
7002
|
-
(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);
|
|
7003
7231
|
runRequired(options.host, "chown", ["root:root", target], "node ownership");
|
|
7004
7232
|
nodeVersion(options.host, target);
|
|
7005
7233
|
return target;
|
|
@@ -7028,8 +7256,8 @@ function validatedOrigin(value) {
|
|
|
7028
7256
|
return value;
|
|
7029
7257
|
}
|
|
7030
7258
|
function readAdoptionSetup(source) {
|
|
7031
|
-
const configPath = (0,
|
|
7032
|
-
if (!(0,
|
|
7259
|
+
const configPath = (0, import_node_path19.join)(source, "config.json");
|
|
7260
|
+
if (!(0, import_node_fs17.existsSync)(configPath)) {
|
|
7033
7261
|
throw new SystemError("invalid-adoption", "adopted installation has no config.json");
|
|
7034
7262
|
}
|
|
7035
7263
|
assertPrivateSourceFile(configPath, "adopted setup");
|
|
@@ -7077,35 +7305,35 @@ function detectUserInstallations(options = {}) {
|
|
|
7077
7305
|
const roots = options.homeRoots ?? ["/home", "/root"];
|
|
7078
7306
|
const found = [];
|
|
7079
7307
|
for (const homeRoot of roots) {
|
|
7080
|
-
if (!(0,
|
|
7081
|
-
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));
|
|
7082
7310
|
for (const home of homes) {
|
|
7083
7311
|
let stat;
|
|
7084
7312
|
try {
|
|
7085
|
-
stat = (0,
|
|
7313
|
+
stat = (0, import_node_fs17.lstatSync)(home);
|
|
7086
7314
|
} catch {
|
|
7087
7315
|
continue;
|
|
7088
7316
|
}
|
|
7089
7317
|
if (!stat.isDirectory()) continue;
|
|
7090
|
-
const unitDir = (0,
|
|
7318
|
+
const unitDir = (0, import_node_path19.join)(home, ".config", "systemd", "user");
|
|
7091
7319
|
let units = [];
|
|
7092
7320
|
try {
|
|
7093
|
-
units = (0,
|
|
7321
|
+
units = (0, import_node_fs17.readdirSync)(unitDir);
|
|
7094
7322
|
} catch {
|
|
7095
7323
|
units = [];
|
|
7096
7324
|
}
|
|
7097
7325
|
for (const unitName2 of units) {
|
|
7098
7326
|
if (!/^rigscope(?:-[0-9a-f]{12})?(?:-(?:hub|collector))?\.service$/.test(unitName2)) continue;
|
|
7099
|
-
const unitPath2 = (0,
|
|
7327
|
+
const unitPath2 = (0, import_node_path19.join)(unitDir, unitName2);
|
|
7100
7328
|
let execStart = null;
|
|
7101
7329
|
try {
|
|
7102
|
-
const line = (0,
|
|
7330
|
+
const line = (0, import_node_fs17.readFileSync)(unitPath2, "utf8").split("\n").find((item) => item.startsWith("ExecStart="));
|
|
7103
7331
|
execStart = line ? line.slice("ExecStart=".length) : null;
|
|
7104
7332
|
} catch {
|
|
7105
7333
|
}
|
|
7106
|
-
const stateCandidates = [(0,
|
|
7107
|
-
const stateDir = stateCandidates.find((candidate) => (0,
|
|
7108
|
-
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 });
|
|
7109
7337
|
}
|
|
7110
7338
|
}
|
|
7111
7339
|
}
|
|
@@ -7113,9 +7341,9 @@ function detectUserInstallations(options = {}) {
|
|
|
7113
7341
|
}
|
|
7114
7342
|
function lockIsLive(path2) {
|
|
7115
7343
|
try {
|
|
7116
|
-
const stat = (0,
|
|
7344
|
+
const stat = (0, import_node_fs17.lstatSync)(path2);
|
|
7117
7345
|
if (!stat.isFile() || stat.size > 4096) return { exists: true, live: false, pid: null, ambiguous: true };
|
|
7118
|
-
const owner = JSON.parse((0,
|
|
7346
|
+
const owner = JSON.parse((0, import_node_fs17.readFileSync)(path2, "utf8"));
|
|
7119
7347
|
const pid = owner.pid;
|
|
7120
7348
|
if (!Number.isSafeInteger(pid) || pid < 1) return { exists: true, live: false, pid: null, ambiguous: true };
|
|
7121
7349
|
try {
|
|
@@ -7133,9 +7361,9 @@ function lockIsLive(path2) {
|
|
|
7133
7361
|
}
|
|
7134
7362
|
function directoryLocks(directory) {
|
|
7135
7363
|
return [
|
|
7136
|
-
(0,
|
|
7137
|
-
(0,
|
|
7138
|
-
(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")
|
|
7139
7367
|
];
|
|
7140
7368
|
}
|
|
7141
7369
|
function assertDirectoryStopped(directory, scope = "local") {
|
|
@@ -7166,13 +7394,13 @@ function assertSystemStartAllowed(paths, components) {
|
|
|
7166
7394
|
}
|
|
7167
7395
|
function detectPowerDriver(moduleRoot = "/sys/module") {
|
|
7168
7396
|
const candidates = ["intel_rapl_msr", "intel_rapl_common", "intel_rapl_tpmi", "intel_rapl", "amd_energy"];
|
|
7169
|
-
return candidates.filter((name) => (0,
|
|
7397
|
+
return candidates.filter((name) => (0, import_node_fs17.existsSync)((0, import_node_path19.join)(moduleRoot, name)));
|
|
7170
7398
|
}
|
|
7171
7399
|
function readPasswd(path2 = "/etc/passwd") {
|
|
7172
7400
|
const users = /* @__PURE__ */ new Map();
|
|
7173
7401
|
let lines;
|
|
7174
7402
|
try {
|
|
7175
|
-
lines = (0,
|
|
7403
|
+
lines = (0, import_node_fs17.readFileSync)(path2, "utf8").split("\n");
|
|
7176
7404
|
} catch {
|
|
7177
7405
|
return users;
|
|
7178
7406
|
}
|
|
@@ -7189,7 +7417,7 @@ function readGroups(path2 = "/etc/group") {
|
|
|
7189
7417
|
const groups = /* @__PURE__ */ new Map();
|
|
7190
7418
|
let lines;
|
|
7191
7419
|
try {
|
|
7192
|
-
lines = (0,
|
|
7420
|
+
lines = (0, import_node_fs17.readFileSync)(path2, "utf8").split("\n");
|
|
7193
7421
|
} catch {
|
|
7194
7422
|
return groups;
|
|
7195
7423
|
}
|
|
@@ -7217,7 +7445,7 @@ function inspectPowerAccess(options = {}) {
|
|
|
7217
7445
|
const sysusers = options.sysusersPath ?? powerSysusersPath(paths);
|
|
7218
7446
|
let ruleText = null;
|
|
7219
7447
|
try {
|
|
7220
|
-
ruleText = (0,
|
|
7448
|
+
ruleText = (0, import_node_fs17.readFileSync)(rulePath, "utf8");
|
|
7221
7449
|
} catch {
|
|
7222
7450
|
ruleText = null;
|
|
7223
7451
|
}
|
|
@@ -7234,27 +7462,27 @@ function inspectPowerAccess(options = {}) {
|
|
|
7234
7462
|
const domains = [];
|
|
7235
7463
|
let entries = [];
|
|
7236
7464
|
try {
|
|
7237
|
-
entries = (0,
|
|
7465
|
+
entries = (0, import_node_fs17.readdirSync)(paths.powercapRoot);
|
|
7238
7466
|
} catch {
|
|
7239
7467
|
entries = [];
|
|
7240
7468
|
}
|
|
7241
7469
|
for (const entry2 of entries.filter((name) => /^intel-rapl:\d+$/.test(name)).sort()) {
|
|
7242
|
-
const domainPath = (0,
|
|
7470
|
+
const domainPath = (0, import_node_path19.join)(paths.powercapRoot, entry2);
|
|
7243
7471
|
let name = entry2;
|
|
7244
7472
|
try {
|
|
7245
|
-
name = (0,
|
|
7473
|
+
name = (0, import_node_fs17.readFileSync)((0, import_node_path19.join)(domainPath, "name"), "utf8").trim() || entry2;
|
|
7246
7474
|
} catch {
|
|
7247
7475
|
}
|
|
7248
7476
|
if (!/^package/.test(name)) continue;
|
|
7249
|
-
const energyPath = (0,
|
|
7250
|
-
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");
|
|
7251
7479
|
const readStat = (path2) => {
|
|
7252
7480
|
if (options.statOverride) {
|
|
7253
7481
|
const override = options.statOverride(path2);
|
|
7254
7482
|
return override === null ? null : { mode: modeString(override.mode), uid: override.uid, gid: override.gid };
|
|
7255
7483
|
}
|
|
7256
7484
|
try {
|
|
7257
|
-
const stat = (0,
|
|
7485
|
+
const stat = (0, import_node_fs17.statSync)(path2);
|
|
7258
7486
|
return { mode: modeString(stat.mode), uid: stat.uid, gid: stat.gid };
|
|
7259
7487
|
} catch {
|
|
7260
7488
|
return null;
|
|
@@ -7288,7 +7516,7 @@ function inspectPowerAccess(options = {}) {
|
|
|
7288
7516
|
problems.push(`collector account ${accounts.collector} is not a member of ${accounts.powerGroup}`);
|
|
7289
7517
|
}
|
|
7290
7518
|
if (!compliant) problems.push(`persistent udev rule is missing or not compliant: ${rulePath}`);
|
|
7291
|
-
if (!(0,
|
|
7519
|
+
if (!(0, import_node_fs17.existsSync)(sysusers)) problems.push(`power sysusers definition is missing: ${sysusers}`);
|
|
7292
7520
|
for (const domain of domains) {
|
|
7293
7521
|
if (!domain.energyExists) problems.push(`${domain.name}: energy_uj is unavailable`);
|
|
7294
7522
|
else if (domain.energy?.worldReadable) problems.push(`${domain.name}: energy_uj is world-readable`);
|
|
@@ -7307,7 +7535,7 @@ function inspectPowerAccess(options = {}) {
|
|
|
7307
7535
|
collectorGids,
|
|
7308
7536
|
group: { name: accounts.powerGroup, exists: group !== null, gid: group?.gid ?? null, members: group?.members ?? [] },
|
|
7309
7537
|
rule: { path: rulePath, present: ruleText !== null, compliant },
|
|
7310
|
-
sysusers: { path: sysusers, present: (0,
|
|
7538
|
+
sysusers: { path: sysusers, present: (0, import_node_fs17.existsSync)(sysusers) },
|
|
7311
7539
|
collectorCanRead,
|
|
7312
7540
|
persistent: compliant && group !== null && collector !== null && group.members.includes(accounts.collector),
|
|
7313
7541
|
worldReadable,
|
|
@@ -7316,14 +7544,14 @@ function inspectPowerAccess(options = {}) {
|
|
|
7316
7544
|
};
|
|
7317
7545
|
}
|
|
7318
7546
|
async function backupDatabase2(source, output, host) {
|
|
7319
|
-
ensureDirectory((0,
|
|
7547
|
+
ensureDirectory((0, import_node_path19.dirname)(output), 448, true);
|
|
7320
7548
|
const db = new import_node_sqlite4.DatabaseSync(source, { readOnly: true, timeout: 5e3 });
|
|
7321
7549
|
try {
|
|
7322
7550
|
await (0, import_node_sqlite4.backup)(db, output);
|
|
7323
7551
|
} finally {
|
|
7324
7552
|
db.close();
|
|
7325
7553
|
}
|
|
7326
|
-
(0,
|
|
7554
|
+
(0, import_node_fs17.chmodSync)(output, 384);
|
|
7327
7555
|
const check = new import_node_sqlite4.DatabaseSync(output, { readOnly: true });
|
|
7328
7556
|
try {
|
|
7329
7557
|
const result = check.prepare("PRAGMA integrity_check").get();
|
|
@@ -7334,7 +7562,7 @@ async function backupDatabase2(source, output, host) {
|
|
|
7334
7562
|
void host;
|
|
7335
7563
|
}
|
|
7336
7564
|
function databaseSchema(path2) {
|
|
7337
|
-
if (!(0,
|
|
7565
|
+
if (!(0, import_node_fs17.existsSync)(path2)) return null;
|
|
7338
7566
|
const db = new import_node_sqlite4.DatabaseSync(path2, { readOnly: true, timeout: 5e3 });
|
|
7339
7567
|
try {
|
|
7340
7568
|
const table = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='schema_migrations'").get();
|
|
@@ -7353,28 +7581,28 @@ function replaceDatabaseFromBackup(backupPath, target, safetyBackup, host) {
|
|
|
7353
7581
|
} finally {
|
|
7354
7582
|
backup3.close();
|
|
7355
7583
|
}
|
|
7356
|
-
ensureDirectory((0,
|
|
7357
|
-
if (safetyBackup !== null && (0,
|
|
7584
|
+
ensureDirectory((0, import_node_path19.dirname)(target), 448, true);
|
|
7585
|
+
if (safetyBackup !== null && (0, import_node_fs17.existsSync)(target)) {
|
|
7358
7586
|
void host;
|
|
7359
7587
|
}
|
|
7360
|
-
const temporary = (0,
|
|
7361
|
-
(0,
|
|
7362
|
-
(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);
|
|
7363
7591
|
for (const sidecar of [`${target}-wal`, `${target}-shm`]) {
|
|
7364
7592
|
try {
|
|
7365
|
-
(0,
|
|
7593
|
+
(0, import_node_fs17.unlinkSync)(sidecar);
|
|
7366
7594
|
} catch {
|
|
7367
7595
|
}
|
|
7368
7596
|
}
|
|
7369
|
-
(0,
|
|
7370
|
-
(0,
|
|
7597
|
+
(0, import_node_fs17.renameSync)(temporary, target);
|
|
7598
|
+
(0, import_node_fs17.chmodSync)(target, 384);
|
|
7371
7599
|
}
|
|
7372
7600
|
function newestTimestamp() {
|
|
7373
7601
|
return (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
7374
7602
|
}
|
|
7375
7603
|
function adoptUserState(options) {
|
|
7376
|
-
const source = (0,
|
|
7377
|
-
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}`);
|
|
7378
7606
|
if (isWithin(options.paths.prefix, source) || isWithin(options.paths.stateDir, source) || isWithin(source, options.paths.stateDir)) {
|
|
7379
7607
|
throw new SystemError("invalid-adoption", "adoption source and system paths must not overlap");
|
|
7380
7608
|
}
|
|
@@ -7384,8 +7612,8 @@ function adoptUserState(options) {
|
|
|
7384
7612
|
const { port, origin } = setup;
|
|
7385
7613
|
if (!Number.isInteger(port) || port < 1 || port > 65535) throw new SystemError("invalid-adoption", "adopted hub port is invalid");
|
|
7386
7614
|
if (options.role !== "collector") {
|
|
7387
|
-
const sourceDatabase = (0,
|
|
7388
|
-
if ((0,
|
|
7615
|
+
const sourceDatabase = (0, import_node_path19.join)(source, "hub", "telemetry.sqlite");
|
|
7616
|
+
if ((0, import_node_fs17.existsSync)(sourceDatabase)) {
|
|
7389
7617
|
assertPrivateSourceFile(sourceDatabase, "adopted database");
|
|
7390
7618
|
const database = new import_node_sqlite4.DatabaseSync(sourceDatabase, { readOnly: true });
|
|
7391
7619
|
try {
|
|
@@ -7395,12 +7623,12 @@ function adoptUserState(options) {
|
|
|
7395
7623
|
database.close();
|
|
7396
7624
|
}
|
|
7397
7625
|
}
|
|
7398
|
-
const sourceEnrollment = (0,
|
|
7399
|
-
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");
|
|
7400
7628
|
}
|
|
7401
7629
|
if (options.role !== "hub") {
|
|
7402
|
-
const sourceCollectorState = (0,
|
|
7403
|
-
if ((0,
|
|
7630
|
+
const sourceCollectorState = (0, import_node_path19.join)(source, "collector", "state.json");
|
|
7631
|
+
if ((0, import_node_fs17.existsSync)(sourceCollectorState)) {
|
|
7404
7632
|
assertPrivateSourceFile(sourceCollectorState, "adopted collector state");
|
|
7405
7633
|
readCollectorIdentity(sourceCollectorState);
|
|
7406
7634
|
}
|
|
@@ -7409,7 +7637,7 @@ function adoptUserState(options) {
|
|
|
7409
7637
|
const warnings = [];
|
|
7410
7638
|
const targetDatabase = hubDatabasePath(options.paths);
|
|
7411
7639
|
const targetCollector = collectorStatePath2(options.paths);
|
|
7412
|
-
if (options.apply && (0,
|
|
7640
|
+
if (options.apply && (0, import_node_fs17.existsSync)(targetDatabase)) {
|
|
7413
7641
|
throw new SystemError("destination-exists", `refusing to overwrite ${targetDatabase}`);
|
|
7414
7642
|
}
|
|
7415
7643
|
const hubEnv = options.role === "collector" ? null : [
|
|
@@ -7444,62 +7672,42 @@ function adoptUserState(options) {
|
|
|
7444
7672
|
port
|
|
7445
7673
|
};
|
|
7446
7674
|
}
|
|
7447
|
-
function copyAdoptedTree(source, target, copied, skipLocks = true) {
|
|
7448
|
-
const visit = (current, destination) => {
|
|
7449
|
-
const stat = (0, import_node_fs16.lstatSync)(current);
|
|
7450
|
-
if (stat.isSymbolicLink()) return;
|
|
7451
|
-
if (stat.isDirectory()) {
|
|
7452
|
-
(0, import_node_fs16.mkdirSync)(destination, { recursive: true, mode: 448 });
|
|
7453
|
-
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));
|
|
7454
|
-
return;
|
|
7455
|
-
}
|
|
7456
|
-
if (!stat.isFile()) return;
|
|
7457
|
-
if (skipLocks && /\.(lock|sock)$/.test(current)) return;
|
|
7458
|
-
(0, import_node_fs16.mkdirSync)((0, import_node_path18.dirname)(destination), { recursive: true, mode: 448 });
|
|
7459
|
-
(0, import_node_fs16.copyFileSync)(current, destination);
|
|
7460
|
-
(0, import_node_fs16.chmodSync)(destination, 384);
|
|
7461
|
-
copied.push({ source: current, target: destination, sha256: sha256File2(destination), bytes: stat.size });
|
|
7462
|
-
};
|
|
7463
|
-
visit(source, target);
|
|
7464
|
-
}
|
|
7465
7675
|
async function performAdoptionCopyAsync(options) {
|
|
7466
7676
|
const { source, paths, role, host, copy } = options;
|
|
7467
7677
|
assertDirectoryStopped(source, role);
|
|
7468
7678
|
const targetDatabase = hubDatabasePath(paths);
|
|
7469
|
-
const sourceDatabase = (0,
|
|
7470
|
-
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)) {
|
|
7471
7681
|
assertPrivateSourceFile(sourceDatabase, "adopted database");
|
|
7472
|
-
ensureDirectory((0,
|
|
7682
|
+
ensureDirectory((0, import_node_path19.join)(paths.stateDir, "hub"), 448, true);
|
|
7473
7683
|
await backupDatabase2(sourceDatabase, targetDatabase, host);
|
|
7474
7684
|
copy.record.files.push({
|
|
7475
7685
|
source: sourceDatabase,
|
|
7476
7686
|
target: targetDatabase,
|
|
7477
7687
|
sha256: sha256File2(targetDatabase),
|
|
7478
|
-
bytes: (0,
|
|
7688
|
+
bytes: (0, import_node_fs17.statSync)(targetDatabase).size
|
|
7479
7689
|
});
|
|
7480
7690
|
}
|
|
7481
|
-
const sourceCollectorState = (0,
|
|
7482
|
-
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)) {
|
|
7483
7693
|
assertPrivateSourceFile(sourceCollectorState, "adopted collector state");
|
|
7484
|
-
ensureDirectory((0,
|
|
7694
|
+
ensureDirectory((0, import_node_path19.join)(paths.stateDir, "collector"), 448, true);
|
|
7485
7695
|
const targetCollector = collectorStatePath2(paths);
|
|
7486
|
-
(0,
|
|
7487
|
-
(0,
|
|
7696
|
+
(0, import_node_fs17.copyFileSync)(sourceCollectorState, targetCollector);
|
|
7697
|
+
(0, import_node_fs17.chmodSync)(targetCollector, 384);
|
|
7488
7698
|
copy.record.files.push({
|
|
7489
7699
|
source: sourceCollectorState,
|
|
7490
7700
|
target: targetCollector,
|
|
7491
7701
|
sha256: sha256File2(targetCollector),
|
|
7492
|
-
bytes: (0,
|
|
7702
|
+
bytes: (0, import_node_fs17.statSync)(targetCollector).size
|
|
7493
7703
|
});
|
|
7494
|
-
const outbox = (0, import_node_path18.join)(source, "collector", "outbox");
|
|
7495
|
-
if ((0, import_node_fs16.existsSync)(outbox)) copyAdoptedTree(outbox, (0, import_node_path18.join)(paths.stateDir, "collector", "outbox"), copy.record.files);
|
|
7496
7704
|
}
|
|
7497
|
-
const enrollment = (0,
|
|
7498
|
-
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)) {
|
|
7499
7707
|
const target = hubEnrollmentPath(paths);
|
|
7500
|
-
(0,
|
|
7501
|
-
(0,
|
|
7502
|
-
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 });
|
|
7503
7711
|
}
|
|
7504
7712
|
}
|
|
7505
7713
|
function writeSysusersFiles(paths, accounts, role, power, host) {
|
|
@@ -7539,15 +7747,15 @@ function writePowerRule(paths, accounts) {
|
|
|
7539
7747
|
writeManagedFile(raplRulePath(paths), renderRaplRule(accounts), 420, true);
|
|
7540
7748
|
}
|
|
7541
7749
|
function powerOriginalPath(paths) {
|
|
7542
|
-
return (0,
|
|
7750
|
+
return (0, import_node_path19.join)(paths.stateDir, POWER_STATE_FILE_NAME);
|
|
7543
7751
|
}
|
|
7544
7752
|
function capturePowerOriginals(paths) {
|
|
7545
7753
|
const files = {};
|
|
7546
7754
|
for (const domain of packageDomainPaths(paths.powercapRoot)) {
|
|
7547
7755
|
for (const name of ["energy_uj", "max_energy_range_uj"]) {
|
|
7548
|
-
const path2 = (0,
|
|
7756
|
+
const path2 = (0, import_node_path19.join)(domain, name);
|
|
7549
7757
|
try {
|
|
7550
|
-
const stat = (0,
|
|
7758
|
+
const stat = (0, import_node_fs17.statSync)(path2);
|
|
7551
7759
|
files[path2] = { mode: stat.mode & 511, uid: stat.uid, gid: stat.gid };
|
|
7552
7760
|
} catch {
|
|
7553
7761
|
}
|
|
@@ -7559,8 +7767,8 @@ function capturePowerOriginals(paths) {
|
|
|
7559
7767
|
function applyPowerAccess(paths, accounts, host) {
|
|
7560
7768
|
for (const domain of packageDomainPaths(paths.powercapRoot)) {
|
|
7561
7769
|
for (const name of ["energy_uj", "max_energy_range_uj"]) {
|
|
7562
|
-
const path2 = (0,
|
|
7563
|
-
if (!(0,
|
|
7770
|
+
const path2 = (0, import_node_path19.join)(domain, name);
|
|
7771
|
+
if (!(0, import_node_fs17.existsSync)(path2)) continue;
|
|
7564
7772
|
runRequired(host, "chgrp", [accounts.powerGroup, path2], `power counter group ${path2}`);
|
|
7565
7773
|
runRequired(host, "chmod", ["0440", path2], `power counter mode ${path2}`);
|
|
7566
7774
|
}
|
|
@@ -7573,9 +7781,9 @@ function resumePowerRule(paths, host) {
|
|
|
7573
7781
|
}
|
|
7574
7782
|
function packageDomainPaths(root) {
|
|
7575
7783
|
try {
|
|
7576
|
-
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) => {
|
|
7577
7785
|
try {
|
|
7578
|
-
return /^package/.test((0,
|
|
7786
|
+
return /^package/.test((0, import_node_fs17.readFileSync)((0, import_node_path19.join)(path2, "name"), "utf8").trim());
|
|
7579
7787
|
} catch {
|
|
7580
7788
|
return false;
|
|
7581
7789
|
}
|
|
@@ -7595,8 +7803,8 @@ function restorePowerOriginals(paths, host) {
|
|
|
7595
7803
|
const files = { ...originals?.files ?? {} };
|
|
7596
7804
|
for (const domain of packageDomainPaths(paths.powercapRoot)) {
|
|
7597
7805
|
for (const name of ["energy_uj", "max_energy_range_uj"]) {
|
|
7598
|
-
const path2 = (0,
|
|
7599
|
-
if (!(0,
|
|
7806
|
+
const path2 = (0, import_node_path19.join)(domain, name);
|
|
7807
|
+
if (!(0, import_node_fs17.existsSync)(path2)) continue;
|
|
7600
7808
|
const original = files[path2];
|
|
7601
7809
|
if (original) {
|
|
7602
7810
|
runRequired(host, "chown", [`${original.uid}:${original.gid}`, path2], "restore counter ownership");
|
|
@@ -7612,7 +7820,7 @@ function restorePowerOriginals(paths, host) {
|
|
|
7612
7820
|
}
|
|
7613
7821
|
}
|
|
7614
7822
|
try {
|
|
7615
|
-
(0,
|
|
7823
|
+
(0, import_node_fs17.unlinkSync)(powerOriginalPath(paths));
|
|
7616
7824
|
} catch {
|
|
7617
7825
|
}
|
|
7618
7826
|
return restored;
|
|
@@ -7636,7 +7844,7 @@ function stopUnits(host, units) {
|
|
|
7636
7844
|
if (units.some((unit) => systemdActive(host, unit))) throw new SystemError("service-active", "system services did not stop; no files were restored");
|
|
7637
7845
|
}
|
|
7638
7846
|
function unitsForCleanup(paths, host) {
|
|
7639
|
-
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));
|
|
7640
7848
|
return [...Object.values(UNIT_NAMES), ...legacy];
|
|
7641
7849
|
}
|
|
7642
7850
|
function startUnits(host, units) {
|
|
@@ -7674,7 +7882,7 @@ async function verifySystemHealth(paths, state, host, timeoutMs, components = en
|
|
|
7674
7882
|
const report = runRequired(
|
|
7675
7883
|
host,
|
|
7676
7884
|
state.nodePath,
|
|
7677
|
-
[(0,
|
|
7885
|
+
[(0, import_node_path19.join)(paths.prefix, "current/dist/ops.cjs"), "inspect", "--database", hubDatabasePath(paths), "--json"],
|
|
7678
7886
|
"activated database verification",
|
|
7679
7887
|
{ timeoutMs: Math.max(100, deadline - Date.now()) }
|
|
7680
7888
|
);
|
|
@@ -7690,8 +7898,8 @@ async function verifySystemHealth(paths, state, host, timeoutMs, components = en
|
|
|
7690
7898
|
let problem = "no sampling marker";
|
|
7691
7899
|
while (Date.now() < deadline) {
|
|
7692
7900
|
try {
|
|
7693
|
-
const marker = readJsonObject((0,
|
|
7694
|
-
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"));
|
|
7695
7903
|
if (marker.pid !== lease.pid || !Number.isSafeInteger(marker.pid)) throw new Error("sampling marker belongs to another process");
|
|
7696
7904
|
process.kill(Number(marker.pid), 0);
|
|
7697
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");
|
|
@@ -7706,12 +7914,12 @@ async function verifySystemHealth(paths, state, host, timeoutMs, components = en
|
|
|
7706
7914
|
}
|
|
7707
7915
|
function chownAccount(paths, owner, group, host) {
|
|
7708
7916
|
for (const path2 of paths) {
|
|
7709
|
-
if (!(0,
|
|
7917
|
+
if (!(0, import_node_fs17.existsSync)(path2)) continue;
|
|
7710
7918
|
runRequired(host, "chown", ["-R", `${owner}:${group}`, path2], `ownership ${path2}`);
|
|
7711
7919
|
}
|
|
7712
7920
|
}
|
|
7713
7921
|
function chmodTree(path2, host) {
|
|
7714
|
-
if (!(0,
|
|
7922
|
+
if (!(0, import_node_fs17.existsSync)(path2)) return;
|
|
7715
7923
|
runRequired(host, "chmod", ["-R", "u=rwX,go=rX", path2], `release permissions ${path2}`);
|
|
7716
7924
|
}
|
|
7717
7925
|
function pickRollbackBackup(state, previousSchema) {
|
|
@@ -7722,9 +7930,12 @@ function pickRollbackBackup(state, previousSchema) {
|
|
|
7722
7930
|
async function recoverFailedUpgrade(options) {
|
|
7723
7931
|
stopUnits(options.host, options.units);
|
|
7724
7932
|
assertDirectoryStopped(options.paths.stateDir);
|
|
7725
|
-
|
|
7726
|
-
|
|
7727
|
-
|
|
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);
|
|
7728
7939
|
const database = hubDatabasePath(options.paths);
|
|
7729
7940
|
let afterSchema = null;
|
|
7730
7941
|
try {
|
|
@@ -7732,13 +7943,13 @@ async function recoverFailedUpgrade(options) {
|
|
|
7732
7943
|
} catch {
|
|
7733
7944
|
afterSchema = null;
|
|
7734
7945
|
}
|
|
7735
|
-
if (options.backupPath !== null && (0,
|
|
7736
|
-
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);
|
|
7737
7948
|
replaceDatabaseFromBackup(options.backupPath, database, null, options.host);
|
|
7738
7949
|
runRequired(options.host, "chown", [`${options.state.accounts.hub}:${options.state.accounts.hub}`, database], "restored database ownership");
|
|
7739
7950
|
}
|
|
7740
|
-
options.state.previousVersion = options.oldPrevious === null ? null : (0,
|
|
7741
|
-
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);
|
|
7742
7953
|
writeSystemState(options.paths, options.state);
|
|
7743
7954
|
if (options.activeComponents.length > 0) {
|
|
7744
7955
|
startUnits(options.host, options.units);
|
|
@@ -7747,14 +7958,14 @@ async function recoverFailedUpgrade(options) {
|
|
|
7747
7958
|
}
|
|
7748
7959
|
function assertManagedFileOwnership(paths, path2) {
|
|
7749
7960
|
if (!isDefaultSystemLayout(paths)) return;
|
|
7750
|
-
if (!(0,
|
|
7751
|
-
const stat = (0,
|
|
7961
|
+
if (!(0, import_node_fs17.existsSync)(path2)) return;
|
|
7962
|
+
const stat = (0, import_node_fs17.lstatSync)(path2);
|
|
7752
7963
|
if (stat.isSymbolicLink() || !stat.isFile()) throw new SystemError("unsafe-path", `${path2} must be a regular managed file`);
|
|
7753
7964
|
if (stat.uid !== 0) throw new SystemError("insecure-ownership", `${path2} must be root-owned before replacement`);
|
|
7754
7965
|
if ((stat.mode & 18) !== 0) throw new SystemError("insecure-permissions", `${path2} must not be group/world-writable`);
|
|
7755
7966
|
}
|
|
7756
7967
|
function writeUnitFile(paths, unit, content, replace) {
|
|
7757
|
-
const path2 = (0,
|
|
7968
|
+
const path2 = (0, import_node_path19.join)(paths.unitsDir, unit);
|
|
7758
7969
|
assertManagedFileOwnership(paths, path2);
|
|
7759
7970
|
writeManagedFile(path2, content, 420, replace);
|
|
7760
7971
|
}
|
|
@@ -7769,19 +7980,19 @@ function ensureComponentSetup(options) {
|
|
|
7769
7980
|
ensureDirectory(paths.configDir, 493);
|
|
7770
7981
|
ensureDirectory(paths.stateDir, 493);
|
|
7771
7982
|
ensureDirectory(paths.unitsDir, 493);
|
|
7772
|
-
ensureDirectory((0,
|
|
7773
|
-
ensureDirectory((0,
|
|
7774
|
-
ensureDirectory((0,
|
|
7775
|
-
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);
|
|
7776
7987
|
const release = currentReleaseOrThrow(paths);
|
|
7777
7988
|
void release;
|
|
7778
7989
|
writeSysusersFiles(paths, accounts, "local", power, host);
|
|
7779
7990
|
if (component === "hub") {
|
|
7780
|
-
if (!(0,
|
|
7991
|
+
if (!(0, import_node_fs17.existsSync)(hubEnvPath(paths))) {
|
|
7781
7992
|
const env = hubEnvTemplate(paths);
|
|
7782
7993
|
writeManagedFile(hubEnvPath(paths), env, 384, false);
|
|
7783
7994
|
}
|
|
7784
|
-
if (!(0,
|
|
7995
|
+
if (!(0, import_node_fs17.existsSync)((0, import_node_path19.join)(paths.unitsDir, UNIT_NAMES.hub))) {
|
|
7785
7996
|
const env = readHubEnvironment(paths);
|
|
7786
7997
|
const remote = env.HUB_PUBLIC_ORIGIN !== void 0 && env.HUB_PUBLIC_ORIGIN !== "";
|
|
7787
7998
|
const unit = renderSystemHubUnit({
|
|
@@ -7798,7 +8009,7 @@ function ensureComponentSetup(options) {
|
|
|
7798
8009
|
`, false);
|
|
7799
8010
|
}
|
|
7800
8011
|
} else {
|
|
7801
|
-
if (!(0,
|
|
8012
|
+
if (!(0, import_node_fs17.existsSync)(collectorEnvPath(paths))) {
|
|
7802
8013
|
writeManagedFile(collectorEnvPath(paths), collectorEnvTemplate(), 384, false);
|
|
7803
8014
|
}
|
|
7804
8015
|
const unit = renderSystemCollectorUnit({
|
|
@@ -7814,17 +8025,17 @@ function ensureComponentSetup(options) {
|
|
|
7814
8025
|
const validation = runRequired(
|
|
7815
8026
|
host,
|
|
7816
8027
|
"systemd-analyze",
|
|
7817
|
-
["verify", "--man=no", (0,
|
|
8028
|
+
["verify", "--man=no", (0, import_node_path19.join)(paths.unitsDir, unitFor(component))],
|
|
7818
8029
|
"native systemd unit validation"
|
|
7819
8030
|
);
|
|
7820
8031
|
if (/path is not absolute|bad unit file|fatal error|unknown (?:key|lvalue)|ignoring/i.test(validation.stderr)) {
|
|
7821
8032
|
throw new SystemError("invalid-unit", "native systemd validation rejected a generated directive");
|
|
7822
8033
|
}
|
|
7823
|
-
if (component === "hub") chownAccount([(0,
|
|
7824
|
-
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);
|
|
7825
8036
|
}
|
|
7826
8037
|
function ensurePowerAccess(paths, accounts, host) {
|
|
7827
|
-
if (!(0,
|
|
8038
|
+
if (!(0, import_node_fs17.existsSync)(powerOriginalPath(paths))) capturePowerOriginals(paths);
|
|
7828
8039
|
writePowerRule(paths, accounts);
|
|
7829
8040
|
resumePowerRule(paths, host);
|
|
7830
8041
|
applyPowerAccess(paths, accounts, host);
|
|
@@ -7842,7 +8053,7 @@ function resetUnfinishedSystemState(options) {
|
|
|
7842
8053
|
}
|
|
7843
8054
|
function installPreset(options, role) {
|
|
7844
8055
|
if (options.adoptFrom !== void 0) {
|
|
7845
|
-
return componentSet(readAdoptionSetup((0,
|
|
8056
|
+
return componentSet(readAdoptionSetup((0, import_node_path19.resolve)(options.adoptFrom)).components);
|
|
7846
8057
|
}
|
|
7847
8058
|
return componentsForRole(role);
|
|
7848
8059
|
}
|
|
@@ -7854,11 +8065,11 @@ function planSystemInstall(options) {
|
|
|
7854
8065
|
const power = options.power !== false && preset.collector;
|
|
7855
8066
|
const initial = options.enable === true ? preset : { hub: false, collector: false };
|
|
7856
8067
|
const files = [
|
|
7857
|
-
{ path: (0,
|
|
8068
|
+
{ path: (0, import_node_path19.join)(paths.prefix, "current"), mode: "symlink", purpose: "active root-owned release" },
|
|
7858
8069
|
{ path: hubEnvPath(paths), mode: "0600", purpose: "root-owned hub configuration" },
|
|
7859
8070
|
{ path: collectorEnvPath(paths), mode: "0600", purpose: "root-owned collector configuration" },
|
|
7860
8071
|
{ path: sysusersPath(paths), mode: "0644", purpose: "dedicated nologin accounts" },
|
|
7861
|
-
...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` }))
|
|
7862
8073
|
];
|
|
7863
8074
|
if (power) {
|
|
7864
8075
|
files.push({ path: raplRulePath(paths), mode: "0644", purpose: "package RAPL read rule" });
|
|
@@ -7873,7 +8084,7 @@ function planSystemInstall(options) {
|
|
|
7873
8084
|
];
|
|
7874
8085
|
const notes = [
|
|
7875
8086
|
"Nothing is changed without --apply and root.",
|
|
7876
|
-
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.",
|
|
7877
8088
|
"One complete package: both runtimes, units and accounts are installed; --role only sets the initial enabled preset.",
|
|
7878
8089
|
"Hub and collector use separate unprivileged accounts; Node gets no capabilities.",
|
|
7879
8090
|
...options.enable && preset.hub ? ["Enabling the hub creates its owner account once and prints the password once."] : [],
|
|
@@ -7906,8 +8117,8 @@ async function installSystemUnlocked(options) {
|
|
|
7906
8117
|
`existing user service(s) detected (${detail}); stop them and use --adopt-user-state for explicit copy-based adoption`
|
|
7907
8118
|
);
|
|
7908
8119
|
}
|
|
7909
|
-
const source = (0,
|
|
7910
|
-
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}`);
|
|
7911
8122
|
const port = options.port ?? 8081;
|
|
7912
8123
|
if (!Number.isInteger(port) || port < 1 || port > 65535) throw new SystemError("invalid-argument", "--port must be 1-65535");
|
|
7913
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) });
|
|
@@ -7928,14 +8139,14 @@ async function installSystemUnlocked(options) {
|
|
|
7928
8139
|
});
|
|
7929
8140
|
try {
|
|
7930
8141
|
if (legacy) resetUnfinishedSystemState({ paths, host, now });
|
|
7931
|
-
ensureDirectory((0,
|
|
8142
|
+
ensureDirectory((0, import_node_path19.join)(paths.prefix, "releases"), 493);
|
|
7932
8143
|
ensureDirectory(paths.stateDir, 493);
|
|
7933
8144
|
ensureDirectory(paths.configDir, 493);
|
|
7934
8145
|
ensureDirectory(paths.unitsDir, 493);
|
|
7935
|
-
ensureDirectory((0,
|
|
7936
|
-
ensureDirectory((0,
|
|
7937
|
-
ensureDirectory((0,
|
|
7938
|
-
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);
|
|
7939
8150
|
const release = commitStagedRelease({ staged, paths, replaceRelease: options.replaceRelease });
|
|
7940
8151
|
let adoption = null;
|
|
7941
8152
|
if (options.adoptFrom) {
|
|
@@ -7968,13 +8179,13 @@ async function installSystemUnlocked(options) {
|
|
|
7968
8179
|
`, true);
|
|
7969
8180
|
writeUnitFile(paths, UNIT_NAMES.collector, `${collectorUnit}
|
|
7970
8181
|
`, true);
|
|
7971
|
-
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");
|
|
7972
8183
|
if (/path is not absolute|bad unit file|fatal error|unknown (?:key|lvalue)|ignoring/i.test(validation.stderr)) {
|
|
7973
8184
|
throw new SystemError("invalid-unit", "native systemd validation rejected a generated directive");
|
|
7974
8185
|
}
|
|
7975
8186
|
if (power) ensurePowerAccess(paths, accounts, host);
|
|
7976
|
-
chownAccount([(0,
|
|
7977
|
-
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);
|
|
7978
8189
|
const state = emptyState({ paths, accounts, role, components: { hub: false, collector: false }, nodePath, now });
|
|
7979
8190
|
state.currentVersion = release.version;
|
|
7980
8191
|
state.releases[release.version] = {
|
|
@@ -7984,7 +8195,7 @@ async function installSystemUnlocked(options) {
|
|
|
7984
8195
|
};
|
|
7985
8196
|
state.adoption = adoption?.record ?? null;
|
|
7986
8197
|
state.power = power ? { enabled: true, rulePath: raplRulePath(paths), group: accounts.powerGroup } : null;
|
|
7987
|
-
replaceSymlink((0,
|
|
8198
|
+
replaceSymlink((0, import_node_path19.join)(paths.prefix, "current"), release.releaseDir, host);
|
|
7988
8199
|
writeSystemState(paths, state);
|
|
7989
8200
|
const wantsHub = preset.hub && (options.enable === true || options.start === true);
|
|
7990
8201
|
const wantsCollector = preset.collector && (options.enable === true || options.start === true);
|
|
@@ -8010,6 +8221,7 @@ async function installSystemUnlocked(options) {
|
|
|
8010
8221
|
await verifySystemHealth(paths, state, host, options.startupTimeoutMs ?? 2e4, started);
|
|
8011
8222
|
}
|
|
8012
8223
|
}
|
|
8224
|
+
recordMachineDataTransition(paths.stateDir, release.version, (path2, content) => atomicWrite(path2, content, 384));
|
|
8013
8225
|
return {
|
|
8014
8226
|
operation: "install",
|
|
8015
8227
|
ok: true,
|
|
@@ -8038,14 +8250,14 @@ function systemStatus(options = {}) {
|
|
|
8038
8250
|
} catch (error2) {
|
|
8039
8251
|
stateError = error2 instanceof Error ? error2.message : String(error2);
|
|
8040
8252
|
}
|
|
8041
|
-
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)));
|
|
8042
8254
|
const publicRole = presentUnits.length === 2 ? "local" : presentUnits[0] === UNIT_NAMES.hub ? "hub" : presentUnits[0] === UNIT_NAMES.collector ? "collector" : null;
|
|
8043
8255
|
const role = state?.role ?? publicRole ?? "local";
|
|
8044
8256
|
const current = currentReleaseDir(paths);
|
|
8045
8257
|
let publicVersion = null;
|
|
8046
8258
|
if (current) {
|
|
8047
8259
|
try {
|
|
8048
|
-
const manifest = JSON.parse((0,
|
|
8260
|
+
const manifest = JSON.parse((0, import_node_fs17.readFileSync)((0, import_node_path19.join)(current, "package.json"), "utf8"));
|
|
8049
8261
|
if (typeof manifest.version === "string") publicVersion = manifest.version;
|
|
8050
8262
|
} catch {
|
|
8051
8263
|
}
|
|
@@ -8056,7 +8268,7 @@ function systemStatus(options = {}) {
|
|
|
8056
8268
|
const componentReports = {};
|
|
8057
8269
|
for (const component of COMPONENTS3) {
|
|
8058
8270
|
const unit = unitFor(component);
|
|
8059
|
-
const present = (0,
|
|
8271
|
+
const present = (0, import_node_fs17.existsSync)((0, import_node_path19.join)(paths.unitsDir, unit));
|
|
8060
8272
|
const active = present && systemdActive(host, unit);
|
|
8061
8273
|
const unitEnabled2 = present && systemdEnabled(host, unit);
|
|
8062
8274
|
const enabled = state !== null ? state.components[component].enabled : unitEnabled2;
|
|
@@ -8065,7 +8277,7 @@ function systemStatus(options = {}) {
|
|
|
8065
8277
|
componentReports[component] = {
|
|
8066
8278
|
component,
|
|
8067
8279
|
unit,
|
|
8068
|
-
path: (0,
|
|
8280
|
+
path: (0, import_node_path19.join)(paths.unitsDir, unit),
|
|
8069
8281
|
present,
|
|
8070
8282
|
enabled,
|
|
8071
8283
|
unitEnabled: unitEnabled2,
|
|
@@ -8109,16 +8321,16 @@ function systemStatus(options = {}) {
|
|
|
8109
8321
|
})),
|
|
8110
8322
|
database: {
|
|
8111
8323
|
path: database,
|
|
8112
|
-
exists: (0,
|
|
8324
|
+
exists: (0, import_node_fs17.existsSync)(database),
|
|
8113
8325
|
schema,
|
|
8114
|
-
mode: (0,
|
|
8326
|
+
mode: (0, import_node_fs17.existsSync)(database) ? modeString((0, import_node_fs17.statSync)(database).mode) : null,
|
|
8115
8327
|
lock
|
|
8116
8328
|
},
|
|
8117
|
-
socket: { path: hubSocketPath(paths), exists: (0,
|
|
8329
|
+
socket: { path: hubSocketPath(paths), exists: (0, import_node_fs17.existsSync)(hubSocketPath(paths)) },
|
|
8118
8330
|
config: {
|
|
8119
8331
|
dir: paths.configDir,
|
|
8120
|
-
hubEnv: { path: hubEnvPath(paths), present: (0,
|
|
8121
|
-
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)) }
|
|
8122
8334
|
},
|
|
8123
8335
|
adoption: state?.adoption ?? null,
|
|
8124
8336
|
power,
|
|
@@ -8287,7 +8499,7 @@ async function enableSystem(options) {
|
|
|
8287
8499
|
],
|
|
8288
8500
|
files: [
|
|
8289
8501
|
{ path: component === "hub" ? hubEnvPath(paths) : collectorEnvPath(paths), mode: "0600", purpose: `${component} configuration` },
|
|
8290
|
-
{ path: (0,
|
|
8502
|
+
{ path: (0, import_node_path19.join)(paths.unitsDir, unitFor(component)), mode: "0644", purpose: `${component} boot unit` }
|
|
8291
8503
|
],
|
|
8292
8504
|
notes: [
|
|
8293
8505
|
"Enables only the requested component; the other component keeps running.",
|
|
@@ -8355,7 +8567,7 @@ function disableSystem(options) {
|
|
|
8355
8567
|
accounts: state.accounts,
|
|
8356
8568
|
commands: [`systemctl stop ${unitFor(component)}`, `systemctl disable ${unitFor(component)}`],
|
|
8357
8569
|
files: [],
|
|
8358
|
-
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."]
|
|
8359
8571
|
};
|
|
8360
8572
|
if (options.apply !== true) return { operation: "disable", ok: true, apply: false, message: "plan only", plan };
|
|
8361
8573
|
assertApply(host);
|
|
@@ -8377,7 +8589,7 @@ function disableSystem(options) {
|
|
|
8377
8589
|
function readPrivateToken(path2, read) {
|
|
8378
8590
|
let stat;
|
|
8379
8591
|
try {
|
|
8380
|
-
stat = (0,
|
|
8592
|
+
stat = (0, import_node_fs17.lstatSync)(path2);
|
|
8381
8593
|
} catch (error2) {
|
|
8382
8594
|
if (error2.code === "ENOENT") {
|
|
8383
8595
|
throw new SystemError("missing-grant", `grant file does not exist: ${path2}`);
|
|
@@ -8388,7 +8600,7 @@ function readPrivateToken(path2, read) {
|
|
|
8388
8600
|
if ((stat.mode & 63) !== 0) throw new SystemError("insecure-permissions", `grant file must be private (0600): ${path2}`);
|
|
8389
8601
|
if (stat.size < 1 || stat.size > 4096) throw new SystemError("invalid-token", `grant file must contain 1-4096 bytes: ${path2}`);
|
|
8390
8602
|
if (!read) return void 0;
|
|
8391
|
-
const token = (0,
|
|
8603
|
+
const token = (0, import_node_fs17.readFileSync)(path2, "utf8").trim();
|
|
8392
8604
|
if (token === "" || /[\r\n\0]/.test(token) || !/^[\x21-\x7e]{1,256}$/.test(token)) {
|
|
8393
8605
|
throw new SystemError("invalid-token", "grant file contains an invalid token");
|
|
8394
8606
|
}
|
|
@@ -8400,7 +8612,7 @@ async function connectSystem(options) {
|
|
|
8400
8612
|
const state = readSystemState(paths);
|
|
8401
8613
|
if (state === null || !state.active) throw new SystemError("not-installed", "no active system installation; run install first");
|
|
8402
8614
|
const destination = connectDestinationUrl(options.url);
|
|
8403
|
-
const tokenFile = (0,
|
|
8615
|
+
const tokenFile = (0, import_node_path19.resolve)(options.tokenFile);
|
|
8404
8616
|
const configured = collectorConfigured(paths);
|
|
8405
8617
|
if (configured.configured) {
|
|
8406
8618
|
throw new SystemError(
|
|
@@ -8448,12 +8660,12 @@ async function connectSystem(options) {
|
|
|
8448
8660
|
`collector enrollment failed: ${error2 instanceof Error ? error2.message : String(error2)}`
|
|
8449
8661
|
);
|
|
8450
8662
|
} finally {
|
|
8451
|
-
chownAccount([(0,
|
|
8663
|
+
chownAccount([(0, import_node_path19.join)(paths.stateDir, "collector")], state.accounts.collector, state.accounts.collector, host);
|
|
8452
8664
|
}
|
|
8453
8665
|
if (!collectorConfigured(paths).configured) {
|
|
8454
8666
|
throw new SystemError("enrollment-failed", "the hub accepted enrollment but no destination was saved; check private state");
|
|
8455
8667
|
}
|
|
8456
|
-
chownAccount([(0,
|
|
8668
|
+
chownAccount([(0, import_node_path19.join)(paths.stateDir, "collector")], state.accounts.collector, state.accounts.collector, host);
|
|
8457
8669
|
writeSystemState(paths, state);
|
|
8458
8670
|
const enabled = state.components.collector.enabled;
|
|
8459
8671
|
if (enabled || wasActive) {
|
|
@@ -8470,13 +8682,16 @@ async function connectSystem(options) {
|
|
|
8470
8682
|
state
|
|
8471
8683
|
};
|
|
8472
8684
|
}
|
|
8685
|
+
function systemMachineDataPaths(paths) {
|
|
8686
|
+
return { database: hubDatabasePath(paths), queueTree: (0, import_node_path19.join)(paths.stateDir, "collector", "outbox") };
|
|
8687
|
+
}
|
|
8473
8688
|
async function upgradeSystemUnlocked(options) {
|
|
8474
8689
|
const host = options.host ?? createSystemHost();
|
|
8475
8690
|
const now = options.now ?? Date.now;
|
|
8476
8691
|
const paths = validateSystemPaths(options.paths);
|
|
8477
8692
|
if (systemStateIsLegacy(paths)) {
|
|
8478
|
-
const source2 = (0,
|
|
8479
|
-
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}`);
|
|
8480
8695
|
const role = legacySystemRole(paths);
|
|
8481
8696
|
const preset = componentsForRole(role);
|
|
8482
8697
|
const enable = options.enable ?? (options.start === true || unitNamesForComponents(preset).some((unit) => systemdEnabled(host, unit)));
|
|
@@ -8499,7 +8714,7 @@ async function upgradeSystemUnlocked(options) {
|
|
|
8499
8714
|
],
|
|
8500
8715
|
files: [
|
|
8501
8716
|
{ path: stateFilePath(paths), mode: "0600", purpose: "canonical replacement state" },
|
|
8502
|
-
{ path: (0,
|
|
8717
|
+
{ path: (0, import_node_path19.join)(paths.stateDir, "backups"), mode: "0700", purpose: "removed with unfinished history" }
|
|
8503
8718
|
],
|
|
8504
8719
|
notes: [
|
|
8505
8720
|
"An unfinished installation is reset, not migrated; its history and credentials are removed.",
|
|
@@ -8532,6 +8747,7 @@ async function upgradeSystemUnlocked(options) {
|
|
|
8532
8747
|
if (state === null || !state.active) throw new SystemError("not-installed", "no active system installation; run install first");
|
|
8533
8748
|
const activeComponents = COMPONENTS3.filter((component) => systemdActive(host, unitFor(component)));
|
|
8534
8749
|
const activeUnits = activeComponents.map(unitFor);
|
|
8750
|
+
const transitionPending = readMachineDataTransition(paths.stateDir) === null;
|
|
8535
8751
|
const plan = {
|
|
8536
8752
|
operation: "upgrade",
|
|
8537
8753
|
apply: options.apply === true,
|
|
@@ -8539,19 +8755,34 @@ async function upgradeSystemUnlocked(options) {
|
|
|
8539
8755
|
components: { hub: state.components.hub.enabled, collector: state.components.collector.enabled },
|
|
8540
8756
|
paths,
|
|
8541
8757
|
accounts: state.accounts,
|
|
8542
|
-
commands: [
|
|
8543
|
-
|
|
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
|
+
],
|
|
8544
8770
|
notes: [
|
|
8545
8771
|
"Staging happens before any service is stopped.",
|
|
8546
8772
|
"The exact active component set is restored; --start does not start a component that was stopped.",
|
|
8547
|
-
"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."]
|
|
8548
8779
|
]
|
|
8549
8780
|
};
|
|
8550
8781
|
if (options.apply !== true) return { operation: "upgrade", ok: true, apply: false, message: "plan only", plan };
|
|
8551
8782
|
assertApply(host);
|
|
8552
8783
|
assertManagedPathSafety(paths, isDefaultSystemLayout(paths));
|
|
8553
|
-
const source = (0,
|
|
8554
|
-
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}`);
|
|
8555
8786
|
const staged = prepareStagedRelease({
|
|
8556
8787
|
source,
|
|
8557
8788
|
paths,
|
|
@@ -8570,21 +8801,22 @@ async function upgradeSystemUnlocked(options) {
|
|
|
8570
8801
|
let backupPath = null;
|
|
8571
8802
|
let beforeSchema = null;
|
|
8572
8803
|
let release = null;
|
|
8804
|
+
let machineData = null;
|
|
8573
8805
|
try {
|
|
8574
8806
|
stopUnits(host, activeUnits);
|
|
8575
8807
|
assertDirectoryStopped(paths.stateDir);
|
|
8576
8808
|
const lock = systemLockState(paths);
|
|
8577
8809
|
if (lock.live) throw new SystemError("duplicate-runtime", `hub did not stop cleanly; lock remains at ${lock.path}`);
|
|
8578
8810
|
const database = hubDatabasePath(paths);
|
|
8579
|
-
if ((0,
|
|
8580
|
-
ensureDirectory((0,
|
|
8811
|
+
if ((0, import_node_fs17.existsSync)(database)) {
|
|
8812
|
+
ensureDirectory((0, import_node_path19.join)(paths.stateDir, "backups"), 448, true);
|
|
8581
8813
|
beforeSchema = databaseSchema(database);
|
|
8582
|
-
backupPath = (0,
|
|
8814
|
+
backupPath = (0, import_node_path19.join)(paths.stateDir, "backups", `pre-upgrade-${staged.version}-${newestTimestamp()}.sqlite`);
|
|
8583
8815
|
await backupDatabase2(database, backupPath, host);
|
|
8584
8816
|
}
|
|
8585
8817
|
release = commitStagedRelease({ staged, paths, replaceRelease: options.replaceRelease });
|
|
8586
|
-
replaceSymlink((0,
|
|
8587
|
-
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);
|
|
8588
8820
|
state.previousVersion = state.currentVersion;
|
|
8589
8821
|
state.currentVersion = release.version;
|
|
8590
8822
|
state.releases[release.version] = {
|
|
@@ -8593,7 +8825,7 @@ async function upgradeSystemUnlocked(options) {
|
|
|
8593
8825
|
installedAt: new Date(now()).toISOString()
|
|
8594
8826
|
};
|
|
8595
8827
|
if (backupPath !== null) {
|
|
8596
|
-
state.backups[(0,
|
|
8828
|
+
state.backups[(0, import_node_path19.basename)(backupPath)] = {
|
|
8597
8829
|
path: backupPath,
|
|
8598
8830
|
schemaVersion: beforeSchema,
|
|
8599
8831
|
fromSchema: beforeSchema,
|
|
@@ -8604,6 +8836,7 @@ async function upgradeSystemUnlocked(options) {
|
|
|
8604
8836
|
};
|
|
8605
8837
|
}
|
|
8606
8838
|
writeSystemState(paths, state);
|
|
8839
|
+
machineData = performMachineDataCleanup(paths.stateDir, systemMachineDataPaths(paths), now);
|
|
8607
8840
|
if (activeComponents.length > 0) {
|
|
8608
8841
|
startUnits(host, activeUnits);
|
|
8609
8842
|
await verifySystemHealth(paths, state, host, options.startupTimeoutMs ?? 2e4, activeComponents);
|
|
@@ -8616,6 +8849,7 @@ async function upgradeSystemUnlocked(options) {
|
|
|
8616
8849
|
oldPrevious,
|
|
8617
8850
|
beforeSchema,
|
|
8618
8851
|
backupPath,
|
|
8852
|
+
machineData,
|
|
8619
8853
|
host,
|
|
8620
8854
|
activeComponents,
|
|
8621
8855
|
units: activeUnits
|
|
@@ -8623,6 +8857,10 @@ async function upgradeSystemUnlocked(options) {
|
|
|
8623
8857
|
throw error2;
|
|
8624
8858
|
}
|
|
8625
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;
|
|
8626
8864
|
return {
|
|
8627
8865
|
operation: "upgrade",
|
|
8628
8866
|
ok: true,
|
|
@@ -8632,6 +8870,7 @@ async function upgradeSystemUnlocked(options) {
|
|
|
8632
8870
|
current: upgraded.releaseDir,
|
|
8633
8871
|
previous: oldCurrent,
|
|
8634
8872
|
backupPath,
|
|
8873
|
+
...machineHistory ? { machineHistory } : {},
|
|
8635
8874
|
state
|
|
8636
8875
|
};
|
|
8637
8876
|
} finally {
|
|
@@ -8639,7 +8878,7 @@ async function upgradeSystemUnlocked(options) {
|
|
|
8639
8878
|
}
|
|
8640
8879
|
}
|
|
8641
8880
|
function systemOperationLockPath(paths) {
|
|
8642
|
-
return (0,
|
|
8881
|
+
return (0, import_node_path19.join)(paths.prefix, "run", "operation.lock");
|
|
8643
8882
|
}
|
|
8644
8883
|
async function withSystemOperation(options, operation) {
|
|
8645
8884
|
if (!options.apply) return operation();
|
|
@@ -8647,7 +8886,7 @@ async function withSystemOperation(options, operation) {
|
|
|
8647
8886
|
assertApply(host);
|
|
8648
8887
|
const paths = validateSystemPaths(options.paths);
|
|
8649
8888
|
ensureDirectory(paths.prefix, 493);
|
|
8650
|
-
ensureDirectory((0,
|
|
8889
|
+
ensureDirectory((0, import_node_path19.join)(paths.prefix, "run"), 448, true);
|
|
8651
8890
|
const release = acquireProcessLease(systemOperationLockPath(paths));
|
|
8652
8891
|
try {
|
|
8653
8892
|
return await operation();
|
|
@@ -8699,24 +8938,24 @@ async function rollbackSystemUnlocked(options = {}) {
|
|
|
8699
8938
|
try {
|
|
8700
8939
|
stopUnits(host, units);
|
|
8701
8940
|
assertDirectoryStopped(paths.stateDir);
|
|
8702
|
-
if (systemLockState(paths).live || lockIsLive((0,
|
|
8941
|
+
if (systemLockState(paths).live || lockIsLive((0, import_node_path19.join)(paths.stateDir, "collector/collector-runtime.lock")).live) {
|
|
8703
8942
|
throw new SystemError("runtime-active", "runtime lease remains after stop; rollback refused");
|
|
8704
8943
|
}
|
|
8705
8944
|
const database = hubDatabasePath(paths);
|
|
8706
|
-
const currentSchema = (0,
|
|
8945
|
+
const currentSchema = (0, import_node_fs17.existsSync)(database) ? databaseSchema(database) : null;
|
|
8707
8946
|
let backupToRestore = null;
|
|
8708
8947
|
if (currentSchema !== null && (previousSchema === null || currentSchema > previousSchema)) {
|
|
8709
8948
|
backupToRestore = pickRollbackBackup(state, previousSchema);
|
|
8710
|
-
if (backupToRestore === null || !(0,
|
|
8949
|
+
if (backupToRestore === null || !(0, import_node_fs17.existsSync)(backupToRestore.path)) {
|
|
8711
8950
|
throw new SystemError(
|
|
8712
8951
|
"incompatible-schema",
|
|
8713
8952
|
`current database schema ${currentSchema} is newer than release ${previousVersion}; no matching pre-upgrade backup is recorded`
|
|
8714
8953
|
);
|
|
8715
8954
|
}
|
|
8716
8955
|
}
|
|
8717
|
-
if ((0,
|
|
8718
|
-
ensureDirectory((0,
|
|
8719
|
-
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`);
|
|
8720
8959
|
await backupDatabase2(database, safetyBackup, host);
|
|
8721
8960
|
}
|
|
8722
8961
|
if (backupToRestore !== null) {
|
|
@@ -8724,8 +8963,8 @@ async function rollbackSystemUnlocked(options = {}) {
|
|
|
8724
8963
|
restoredDatabase = true;
|
|
8725
8964
|
runRequired(host, "chown", [`${state.accounts.hub}:${state.accounts.hub}`, database], "restored database ownership");
|
|
8726
8965
|
}
|
|
8727
|
-
replaceSymlink((0,
|
|
8728
|
-
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);
|
|
8729
8968
|
state.previousVersion = state.currentVersion;
|
|
8730
8969
|
state.currentVersion = previousVersion;
|
|
8731
8970
|
state.updatedAt = new Date(now()).toISOString();
|
|
@@ -8747,10 +8986,10 @@ async function rollbackSystemUnlocked(options = {}) {
|
|
|
8747
8986
|
};
|
|
8748
8987
|
} catch (error2) {
|
|
8749
8988
|
stopUnits(host, units);
|
|
8750
|
-
replaceSymlink((0,
|
|
8751
|
-
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);
|
|
8752
8991
|
if (restoredDatabase && safetyBackup) {
|
|
8753
|
-
const failed = (0,
|
|
8992
|
+
const failed = (0, import_node_path19.join)(paths.stateDir, "backups", `failed-rollback-${newestTimestamp()}.sqlite`);
|
|
8754
8993
|
await backupDatabase2(hubDatabasePath(paths), failed, host);
|
|
8755
8994
|
replaceDatabaseFromBackup(safetyBackup, hubDatabasePath(paths), null, host);
|
|
8756
8995
|
runRequired(host, "chown", [`${state.accounts.hub}:${state.accounts.hub}`, hubDatabasePath(paths)], "restored database ownership");
|
|
@@ -8807,31 +9046,31 @@ function uninstallSystem(options = {}) {
|
|
|
8807
9046
|
assertDirectoryStopped(paths.stateDir);
|
|
8808
9047
|
for (const unit of units) runMaybe(host, "systemctl", ["disable", unit]);
|
|
8809
9048
|
for (const unit of units) {
|
|
8810
|
-
const path2 = (0,
|
|
9049
|
+
const path2 = (0, import_node_path19.join)(paths.unitsDir, unit);
|
|
8811
9050
|
assertManagedFileOwnership(paths, path2);
|
|
8812
9051
|
try {
|
|
8813
|
-
(0,
|
|
9052
|
+
(0, import_node_fs17.unlinkSync)(path2);
|
|
8814
9053
|
} catch {
|
|
8815
9054
|
}
|
|
8816
9055
|
}
|
|
8817
9056
|
runMaybe(host, "systemctl", ["daemon-reload"]);
|
|
8818
|
-
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));
|
|
8819
9058
|
if (hadPowerAccess) {
|
|
8820
9059
|
try {
|
|
8821
|
-
(0,
|
|
9060
|
+
(0, import_node_fs17.unlinkSync)(raplRulePath(paths));
|
|
8822
9061
|
} catch {
|
|
8823
9062
|
}
|
|
8824
9063
|
try {
|
|
8825
|
-
(0,
|
|
9064
|
+
(0, import_node_fs17.unlinkSync)(powerSysusersPath(paths));
|
|
8826
9065
|
} catch {
|
|
8827
9066
|
}
|
|
8828
9067
|
restorePowerOriginals(paths, host);
|
|
8829
9068
|
resumePowerRule(paths, host);
|
|
8830
9069
|
}
|
|
8831
|
-
removeSymlink((0,
|
|
8832
|
-
removeSymlink((0,
|
|
8833
|
-
(0,
|
|
8834
|
-
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 });
|
|
8835
9074
|
if (state !== null) {
|
|
8836
9075
|
state.active = false;
|
|
8837
9076
|
state.power = null;
|
|
@@ -8844,8 +9083,8 @@ function uninstallSystem(options = {}) {
|
|
|
8844
9083
|
for (const group of [accounts.powerGroup, accounts.hub, accounts.collector]) runMaybe(host, "groupdel", [group]);
|
|
8845
9084
|
}
|
|
8846
9085
|
if (options.purgeData === true) {
|
|
8847
|
-
(0,
|
|
8848
|
-
(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 });
|
|
8849
9088
|
}
|
|
8850
9089
|
return {
|
|
8851
9090
|
operation: "uninstall",
|
|
@@ -8895,7 +9134,7 @@ function grantPower(options = {}) {
|
|
|
8895
9134
|
writeManagedFile(powerSysusersPath(paths), renderPowerSysusers(paths, accounts), 420, true);
|
|
8896
9135
|
runRequired(host, "systemd-sysusers", [], "power group creation");
|
|
8897
9136
|
assertSystemAccounts(host, accounts, true, ["collector"]);
|
|
8898
|
-
if (!(0,
|
|
9137
|
+
if (!(0, import_node_fs17.existsSync)(powerOriginalPath(paths))) capturePowerOriginals(paths);
|
|
8899
9138
|
writePowerRule(paths, accounts);
|
|
8900
9139
|
resumePowerRule(paths, host);
|
|
8901
9140
|
applyPowerAccess(paths, accounts, host);
|
|
@@ -8924,11 +9163,11 @@ function revokePower(options = {}) {
|
|
|
8924
9163
|
if (options.apply !== true) return { operation: "power-revoke", ok: true, apply: false, message: "plan only", plan };
|
|
8925
9164
|
assertApply(host);
|
|
8926
9165
|
try {
|
|
8927
|
-
(0,
|
|
9166
|
+
(0, import_node_fs17.unlinkSync)(raplRulePath(paths));
|
|
8928
9167
|
} catch {
|
|
8929
9168
|
}
|
|
8930
9169
|
try {
|
|
8931
|
-
(0,
|
|
9170
|
+
(0, import_node_fs17.unlinkSync)(powerSysusersPath(paths));
|
|
8932
9171
|
} catch {
|
|
8933
9172
|
}
|
|
8934
9173
|
restorePowerOriginals(paths, host);
|
|
@@ -9144,6 +9383,12 @@ function printMutationReport(report) {
|
|
|
9144
9383
|
console.log("then run `rigscope system connect https://<hub> --token-file <file> --apply`.");
|
|
9145
9384
|
}
|
|
9146
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
|
+
}
|
|
9147
9392
|
async function runSystemCommand(argv) {
|
|
9148
9393
|
const parsed = parseSystemArgs(argv);
|
|
9149
9394
|
if (parsed.command === "help") {
|
|
@@ -9215,7 +9460,7 @@ ${humanPlan(report.plan)}`);
|
|
|
9215
9460
|
if (parsed.command === "logs") {
|
|
9216
9461
|
const selected = validateSystemPaths(paths);
|
|
9217
9462
|
const component = componentFrom(parsed, false);
|
|
9218
|
-
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)));
|
|
9219
9464
|
if (units.length === 0) throw new SystemError("not-installed", component ? `${component} logs are unavailable; its unit is not installed` : "no system services installed");
|
|
9220
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" });
|
|
9221
9466
|
if (result.error) throw result.error;
|
|
@@ -9291,6 +9536,7 @@ ${humanPlan(report.plan)}`);
|
|
|
9291
9536
|
else {
|
|
9292
9537
|
printMutationReport(report);
|
|
9293
9538
|
console.log(`Backup: ${report.backupPath ?? "none"}`);
|
|
9539
|
+
printMachineDataOutcome(report.machineHistory);
|
|
9294
9540
|
}
|
|
9295
9541
|
return 0;
|
|
9296
9542
|
}
|
|
@@ -9396,7 +9642,7 @@ if (isMainModule()) {
|
|
|
9396
9642
|
}
|
|
9397
9643
|
|
|
9398
9644
|
// src/cli/selection.ts
|
|
9399
|
-
var
|
|
9645
|
+
var import_node_fs18 = require("node:fs");
|
|
9400
9646
|
function selectInstallation(options) {
|
|
9401
9647
|
if (options.scope !== void 0 && options.scope !== "user" && options.scope !== "system") {
|
|
9402
9648
|
throw new Error("--scope must be user or system.");
|
|
@@ -9412,16 +9658,16 @@ function selectInstallation(options) {
|
|
|
9412
9658
|
return options.systemPresent ? "system" : "user";
|
|
9413
9659
|
}
|
|
9414
9660
|
function systemInstallationPresent() {
|
|
9415
|
-
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");
|
|
9416
9662
|
}
|
|
9417
9663
|
|
|
9418
9664
|
// src/cli/access.ts
|
|
9419
|
-
var
|
|
9420
|
-
var
|
|
9421
|
-
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");
|
|
9422
9668
|
|
|
9423
9669
|
// collector/destinations/outbox.ts
|
|
9424
|
-
var
|
|
9670
|
+
var import_node_crypto13 = require("node:crypto");
|
|
9425
9671
|
var path = __toESM(require("node:path"));
|
|
9426
9672
|
var import_node_sqlite5 = require("node:sqlite");
|
|
9427
9673
|
var DEFAULT_OUTBOX_LIMITS = {
|
|
@@ -9433,7 +9679,7 @@ var DEFAULT_OUTBOX_LIMITS = {
|
|
|
9433
9679
|
var DEFAULT_OUTBOX_DISK_BYTES = 80 * 1024 * 1024;
|
|
9434
9680
|
var WRITE_HEADROOM_BYTES = 16 * 1024;
|
|
9435
9681
|
function outboxDirFor(stateDir, url) {
|
|
9436
|
-
const digest = (0,
|
|
9682
|
+
const digest = (0, import_node_crypto13.createHash)("sha256").update(url, "utf8").digest("hex").slice(0, 16);
|
|
9437
9683
|
return path.join(stateDir, "outbox", digest);
|
|
9438
9684
|
}
|
|
9439
9685
|
|
|
@@ -9443,7 +9689,7 @@ function endpointFor(config) {
|
|
|
9443
9689
|
}
|
|
9444
9690
|
function readCollectorState(dir) {
|
|
9445
9691
|
try {
|
|
9446
|
-
return JSON.parse(readPrivate((0,
|
|
9692
|
+
return JSON.parse(readPrivate((0, import_node_path20.join)(dir, "collector", "state.json")));
|
|
9447
9693
|
} catch (error2) {
|
|
9448
9694
|
if (error2.code === "ENOENT") return null;
|
|
9449
9695
|
throw error2;
|
|
@@ -9468,7 +9714,7 @@ function planAccessChange(dir, options) {
|
|
|
9468
9714
|
delete next.socket;
|
|
9469
9715
|
} else if (options.origin) {
|
|
9470
9716
|
next.origin = options.origin;
|
|
9471
|
-
next.socket = options.socket ?? (0,
|
|
9717
|
+
next.socket = options.socket ?? (0, import_node_path20.join)(dir, "run", "hub.sock");
|
|
9472
9718
|
}
|
|
9473
9719
|
parseHubConfig(hubEnvironment(dir, next));
|
|
9474
9720
|
const oldEndpoint = endpointFor(previous);
|
|
@@ -9484,8 +9730,8 @@ function planAccessChange(dir, options) {
|
|
|
9484
9730
|
collectorChanged,
|
|
9485
9731
|
oldEndpoint,
|
|
9486
9732
|
newEndpoint,
|
|
9487
|
-
oldQueue: collectorChanged ? outboxDirFor((0,
|
|
9488
|
-
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,
|
|
9489
9735
|
state,
|
|
9490
9736
|
self
|
|
9491
9737
|
};
|
|
@@ -9493,22 +9739,22 @@ function planAccessChange(dir, options) {
|
|
|
9493
9739
|
function configureAccess(dir, options) {
|
|
9494
9740
|
const plan = planAccessChange(dir, options);
|
|
9495
9741
|
if (!plan.changed) return { changed: false, backup: null, url: plan.url };
|
|
9496
|
-
const configPath = (0,
|
|
9497
|
-
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");
|
|
9498
9744
|
const beforeConfig = readPrivate(configPath);
|
|
9499
9745
|
const beforeState = plan.state === null ? null : readPrivate(statePath);
|
|
9500
|
-
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)) {
|
|
9501
9747
|
throw new Error("The destination already has an outbox. Preserve or replay it before changing access.");
|
|
9502
9748
|
}
|
|
9503
|
-
if (plan.oldQueue && (0,
|
|
9504
|
-
const stat = (0,
|
|
9749
|
+
if (plan.oldQueue && (0, import_node_fs19.existsSync)(plan.oldQueue)) {
|
|
9750
|
+
const stat = (0, import_node_fs19.lstatSync)(plan.oldQueue);
|
|
9505
9751
|
if (!stat.isDirectory() || stat.isSymbolicLink()) throw new Error("Collector outbox must be a real directory.");
|
|
9506
9752
|
}
|
|
9507
|
-
const backup3 = (0,
|
|
9753
|
+
const backup3 = (0, import_node_path20.join)(dir, "backups", `access-${(0, import_node_crypto14.randomUUID)()}`);
|
|
9508
9754
|
privateDirectory(backup3);
|
|
9509
|
-
writePrivateFile((0,
|
|
9510
|
-
if (beforeState !== null) writePrivateFile((0,
|
|
9511
|
-
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({
|
|
9512
9758
|
oldEndpoint: plan.collectorChanged ? plan.oldEndpoint : null,
|
|
9513
9759
|
newEndpoint: plan.collectorChanged ? plan.newEndpoint : null,
|
|
9514
9760
|
oldQueue: plan.oldQueue,
|
|
@@ -9516,8 +9762,8 @@ function configureAccess(dir, options) {
|
|
|
9516
9762
|
}));
|
|
9517
9763
|
let movedQueue = false;
|
|
9518
9764
|
try {
|
|
9519
|
-
if (plan.oldQueue && plan.newQueue && plan.oldQueue !== plan.newQueue && (0,
|
|
9520
|
-
(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);
|
|
9521
9767
|
movedQueue = true;
|
|
9522
9768
|
}
|
|
9523
9769
|
if (plan.collectorChanged && plan.state && plan.self) {
|
|
@@ -9533,7 +9779,7 @@ function configureAccess(dir, options) {
|
|
|
9533
9779
|
try {
|
|
9534
9780
|
writePrivateFile(configPath, beforeConfig);
|
|
9535
9781
|
if (beforeState !== null) writePrivateFile(statePath, beforeState);
|
|
9536
|
-
if (movedQueue) (0,
|
|
9782
|
+
if (movedQueue) (0, import_node_fs19.renameSync)(plan.newQueue, plan.oldQueue);
|
|
9537
9783
|
} catch {
|
|
9538
9784
|
throw new Error(`Access change could not be recovered. Keep the service stopped and restore configuration from ${backup3}.`);
|
|
9539
9785
|
}
|
|
@@ -9543,7 +9789,7 @@ function configureAccess(dir, options) {
|
|
|
9543
9789
|
}
|
|
9544
9790
|
|
|
9545
9791
|
// src/cli/main.ts
|
|
9546
|
-
var ROOT = (0,
|
|
9792
|
+
var ROOT = (0, import_node_path21.resolve)(__dirname, "..");
|
|
9547
9793
|
var HELP2 = `Rigscope \u2014 your machines, in view
|
|
9548
9794
|
|
|
9549
9795
|
Usage: rigscope <command> [options]
|
|
@@ -9664,7 +9910,7 @@ async function readPassword() {
|
|
|
9664
9910
|
}
|
|
9665
9911
|
}
|
|
9666
9912
|
function passwordFromFile(path2) {
|
|
9667
|
-
const raw = readPrivate((0,
|
|
9913
|
+
const raw = readPrivate((0, import_node_path21.resolve)(path2));
|
|
9668
9914
|
return raw.replace(/\r?\n$/, "");
|
|
9669
9915
|
}
|
|
9670
9916
|
function healthDeadline(value) {
|
|
@@ -9705,7 +9951,12 @@ function announce(setup, dir) {
|
|
|
9705
9951
|
Password: ${setup.password}`);
|
|
9706
9952
|
printWarning("Save this password; it is shown once.");
|
|
9707
9953
|
}
|
|
9708
|
-
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);
|
|
9709
9960
|
}
|
|
9710
9961
|
async function main() {
|
|
9711
9962
|
const argv = process.argv.slice(2);
|
|
@@ -9745,7 +9996,7 @@ async function main() {
|
|
|
9745
9996
|
return 0;
|
|
9746
9997
|
}
|
|
9747
9998
|
if (values.version) {
|
|
9748
|
-
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);
|
|
9749
10000
|
return 0;
|
|
9750
10001
|
}
|
|
9751
10002
|
if (process.platform !== "linux") throw new Error("Rigscope currently supports Linux.");
|
|
@@ -9777,13 +10028,13 @@ async function main() {
|
|
|
9777
10028
|
if (value !== void 0 && key !== "state-dir" && key !== "scope" && !(permitted[command] ?? []).includes(key)) throw new Error(`--${key} is not available for ${command}.`);
|
|
9778
10029
|
}
|
|
9779
10030
|
if (values.origin?.endsWith("/")) values.origin = values.origin.slice(0, -1);
|
|
9780
|
-
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;
|
|
9781
10032
|
const dir = stateDirectory(values["state-dir"] ?? (command === "try" ? `${stateDirectory()}-trial` : process.env.RIGSCOPE_STATE_DIR ?? managedState));
|
|
9782
10033
|
const explicitState = Boolean(values["state-dir"] || process.env.RIGSCOPE_STATE_DIR || managedState || command === "try" || command === "run");
|
|
9783
10034
|
const scope = selectInstallation({
|
|
9784
10035
|
scope: values.scope ?? (explicitState ? "user" : void 0),
|
|
9785
10036
|
explicitState: Boolean(values["state-dir"]),
|
|
9786
|
-
userPresent: (0,
|
|
10037
|
+
userPresent: (0, import_node_fs20.existsSync)((0, import_node_path21.join)(dir, "config.json")),
|
|
9787
10038
|
systemPresent: systemInstallationPresent()
|
|
9788
10039
|
});
|
|
9789
10040
|
if (scope === "system") {
|
|
@@ -9793,7 +10044,7 @@ async function main() {
|
|
|
9793
10044
|
throw new Error(`System installation selected. Use rigscope system ${command} (mutations require sudo and --apply), or --scope user for a user installation.`);
|
|
9794
10045
|
}
|
|
9795
10046
|
if (command === "config") {
|
|
9796
|
-
console.log((0,
|
|
10047
|
+
console.log((0, import_node_path21.join)(dir, "config.json"));
|
|
9797
10048
|
return 0;
|
|
9798
10049
|
}
|
|
9799
10050
|
if (command === "upgrade" && installationNeedsReset(dir)) {
|
|
@@ -9824,7 +10075,7 @@ async function main() {
|
|
|
9824
10075
|
if (values.enable && values["no-enable"]) throw new Error("Choose --enable or --no-enable.");
|
|
9825
10076
|
if (values.boot && values["no-enable"]) throw new Error("--boot requires startup to be enabled.");
|
|
9826
10077
|
}
|
|
9827
|
-
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;
|
|
9828
10079
|
let recoveryPassword;
|
|
9829
10080
|
if (command === "recover-password") {
|
|
9830
10081
|
const saved = readSetup(dir);
|
|
@@ -9862,7 +10113,7 @@ async function main() {
|
|
|
9862
10113
|
}
|
|
9863
10114
|
if (command === "try") {
|
|
9864
10115
|
if (values.role && values.role !== "local") throw new Error("Use install for a hub or collector.");
|
|
9865
|
-
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.");
|
|
9866
10117
|
const setup = initialize(dir, { role: "local", port: values.port ?? "8082" });
|
|
9867
10118
|
console.log("Trial: foreground hub + collector. Ctrl+C stops both.");
|
|
9868
10119
|
announce(setup, dir);
|
|
@@ -9878,20 +10129,20 @@ async function main() {
|
|
|
9878
10129
|
const releases = [];
|
|
9879
10130
|
try {
|
|
9880
10131
|
releases.push(acquireProcessLease(componentLeasePath(dir, "collector")));
|
|
9881
|
-
releases.push(acquireProcessLease((0,
|
|
9882
|
-
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);
|
|
9883
10134
|
} finally {
|
|
9884
10135
|
for (const release of releases.reverse()) release();
|
|
9885
10136
|
}
|
|
9886
10137
|
configureComponent(dir, "collector", { enabled: true, pairColocated: false });
|
|
9887
|
-
if ((0,
|
|
10138
|
+
if ((0, import_node_fs20.existsSync)((0, import_node_path21.join)(dir, "runtime"))) {
|
|
9888
10139
|
writeService(dir, "collector");
|
|
9889
10140
|
systemctl(dir, "enable", false, "collector");
|
|
9890
10141
|
}
|
|
9891
|
-
if (!values["no-start"] && !values["no-restart"] && (0,
|
|
10142
|
+
if (!values["no-start"] && !values["no-restart"] && (0, import_node_fs20.existsSync)(unitPath(dir, "collector"))) {
|
|
9892
10143
|
console.log(`Hub connected. Background service ${await startInstallation(dir, "collector")}.`);
|
|
9893
10144
|
} else {
|
|
9894
|
-
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)}`}.`);
|
|
9895
10146
|
}
|
|
9896
10147
|
return 0;
|
|
9897
10148
|
}
|
|
@@ -9900,10 +10151,10 @@ async function main() {
|
|
|
9900
10151
|
const existing = readSetup(dir);
|
|
9901
10152
|
if (!existing) throw new Error("No saved installation. Run rigscope install first.");
|
|
9902
10153
|
if (command === "enable") {
|
|
9903
|
-
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.");
|
|
9904
10155
|
if (target === "hub" && (existing.users.length > 0 || existing.origin) && (values.origin !== void 0 || values.socket !== void 0 || values.port !== void 0)) {
|
|
9905
10156
|
const nextOrigin = values.origin !== void 0 ? values.origin : existing.origin;
|
|
9906
|
-
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;
|
|
9907
10158
|
const nextPort = values.port !== void 0 ? Number(values.port) : existing.port;
|
|
9908
10159
|
if (nextOrigin !== existing.origin || nextSocket !== existing.socket || nextPort !== existing.port) {
|
|
9909
10160
|
throw new Error("Change hub access with rigscope configure.");
|
|
@@ -9941,7 +10192,7 @@ Save this password; it is shown once.`);
|
|
|
9941
10192
|
if (values.boot && values["no-enable"]) throw new Error("--boot requires startup to be enabled.");
|
|
9942
10193
|
const resetting = installationNeedsReset(dir);
|
|
9943
10194
|
if (resetting) values.role = values.role ?? installationRole(dir);
|
|
9944
|
-
const release = resetting || serviceActive(dir) && (0,
|
|
10195
|
+
const release = resetting || serviceActive(dir) && (0, import_node_fs20.existsSync)((0, import_node_path21.join)(dir, "runtime")) ? () => {
|
|
9945
10196
|
} : acquireProcessLease(combinedLeasePath(dir));
|
|
9946
10197
|
let alias;
|
|
9947
10198
|
let installedVersion;
|
|
@@ -9949,7 +10200,7 @@ Save this password; it is shown once.`);
|
|
|
9949
10200
|
if (resetting) {
|
|
9950
10201
|
console.log("Old installation state detected. Resetting configuration and history, then installing the replacement\u2026");
|
|
9951
10202
|
validateSetupOptions({ role: values.role, port: values.port, origin: values.origin, socket: values.socket });
|
|
9952
|
-
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;
|
|
9953
10204
|
const stage = stagePackage(ROOT, dir, source);
|
|
9954
10205
|
let setup;
|
|
9955
10206
|
try {
|
|
@@ -9959,26 +10210,27 @@ Save this password; it is shown once.`);
|
|
|
9959
10210
|
setup: { role: values.role, port: values.port, origin: values.origin, socket: values.socket }
|
|
9960
10211
|
});
|
|
9961
10212
|
} catch (error2) {
|
|
9962
|
-
(0,
|
|
10213
|
+
(0, import_node_fs20.rmSync)(stage, { recursive: true, force: true });
|
|
9963
10214
|
throw error2;
|
|
9964
10215
|
}
|
|
9965
10216
|
announce(setup, dir);
|
|
9966
|
-
installedVersion = runtimeVersion((0,
|
|
10217
|
+
installedVersion = runtimeVersion((0, import_node_path21.join)(dir, "runtime"));
|
|
9967
10218
|
writeRuntimeState(dir, { ...readRuntimeState(dir) ?? emptyRuntimeState(dir), currentVersion: installedVersion });
|
|
9968
10219
|
} else {
|
|
9969
10220
|
const setup = initialize(dir, { role: values.role, port: values.port, origin: values.origin, socket: values.socket });
|
|
9970
10221
|
announce(setup, dir);
|
|
9971
|
-
if ((0,
|
|
10222
|
+
if ((0, import_node_fs20.existsSync)((0, import_node_path21.join)(dir, "runtime"))) {
|
|
9972
10223
|
if (values.from) throw new Error("Runtime already installed. Use rigscope upgrade --from <package>.");
|
|
9973
10224
|
} else {
|
|
9974
10225
|
console.log("Installing runtime\u2026");
|
|
9975
|
-
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;
|
|
9976
10227
|
const stage = stagePackage(ROOT, dir, source);
|
|
9977
10228
|
activatePackage(dir, stage);
|
|
9978
10229
|
}
|
|
9979
|
-
installedVersion = runtimeVersion((0,
|
|
10230
|
+
installedVersion = runtimeVersion((0, import_node_path21.join)(dir, "runtime"));
|
|
9980
10231
|
writeRuntimeState(dir, { ...readRuntimeState(dir) ?? emptyRuntimeState(dir), currentVersion: installedVersion });
|
|
9981
10232
|
}
|
|
10233
|
+
recordMachineDataTransition(dir, installedVersion);
|
|
9982
10234
|
writeService(dir);
|
|
9983
10235
|
alias = installAlias(dir, ROOT);
|
|
9984
10236
|
const installedConfig = readSetup(dir);
|
|
@@ -10024,7 +10276,7 @@ Services: ${components2.map((target) => unitName(dir, target)).join(", ")}`);
|
|
|
10024
10276
|
}
|
|
10025
10277
|
const startup = startupStatus(dir);
|
|
10026
10278
|
console.log(`Startup: ${!startup.enabled ? "manual" : startup.linger ? "at boot; continues after logout" : "at login; use install --boot to continue after logout"}`);
|
|
10027
|
-
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.`);
|
|
10028
10280
|
return 0;
|
|
10029
10281
|
}
|
|
10030
10282
|
if (command === "doctor") {
|
|
@@ -10040,7 +10292,7 @@ Services: ${components2.map((target) => unitName(dir, target)).join(", ")}`);
|
|
|
10040
10292
|
const config = readSetup(dir);
|
|
10041
10293
|
if (!config) {
|
|
10042
10294
|
if (command === "status") {
|
|
10043
|
-
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}
|
|
10044
10296
|
No user installation.
|
|
10045
10297
|
Install background monitoring: rigscope install --boot
|
|
10046
10298
|
Connect to a hub: rigscope install --role collector --boot
|
|
@@ -10061,25 +10313,25 @@ ${bold("Components")}:`);
|
|
|
10061
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)"}`);
|
|
10062
10314
|
if (service.active && service.execMainPid) console.log(` PID ${service.execMainPid}`);
|
|
10063
10315
|
}
|
|
10064
|
-
console.log(`Configuration: ${(0,
|
|
10316
|
+
console.log(`Configuration: ${(0, import_node_path21.join)(dir, "config.json")}
|
|
10065
10317
|
Startup: ${!startup.enabled ? "manual" : startup.linger ? "at boot; continues after logout" : "at login only"}
|
|
10066
|
-
CLI version: ${JSON.parse((0,
|
|
10067
|
-
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"))) {
|
|
10068
10320
|
try {
|
|
10069
|
-
console.log(`Runtime: rigscope ${runtimeVersion((0,
|
|
10321
|
+
console.log(`Runtime: rigscope ${runtimeVersion((0, import_node_path21.join)(dir, "runtime"))}`);
|
|
10070
10322
|
} catch {
|
|
10071
10323
|
console.log("Runtime: invalid (run rigscope doctor)");
|
|
10072
10324
|
}
|
|
10073
10325
|
}
|
|
10074
|
-
if ((0,
|
|
10326
|
+
if ((0, import_node_fs20.existsSync)((0, import_node_path21.join)(dir, "runtime-previous"))) {
|
|
10075
10327
|
try {
|
|
10076
|
-
console.log(`Previous runtime: rigscope ${runtimeVersion((0,
|
|
10328
|
+
console.log(`Previous runtime: rigscope ${runtimeVersion((0, import_node_path21.join)(dir, "runtime-previous"))}`);
|
|
10077
10329
|
} catch {
|
|
10078
10330
|
console.log("Previous runtime: invalid");
|
|
10079
10331
|
}
|
|
10080
10332
|
}
|
|
10081
10333
|
const releaseState = readRuntimeState(dir);
|
|
10082
|
-
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)) : [];
|
|
10083
10335
|
if (paired.length > 0) console.log(`Paired database backups: ${paired.length}`);
|
|
10084
10336
|
const hubConfigured2 = config.users.length > 0;
|
|
10085
10337
|
if (hubConfigured2) console.log(`Hub: ${config.origin ?? `http://127.0.0.1:${config.port}`}`);
|
|
@@ -10088,8 +10340,8 @@ CLI version: ${JSON.parse((0, import_node_fs19.readFileSync)((0, import_node_pat
|
|
|
10088
10340
|
console.log(`Health: ${health.ok ? "ok" : health.error}
|
|
10089
10341
|
Running version: ${health.body?.version ?? "unavailable"}`);
|
|
10090
10342
|
}
|
|
10091
|
-
const state = (0,
|
|
10092
|
-
if ((0,
|
|
10343
|
+
const state = (0, import_node_path21.join)(dir, "collector", "state.json");
|
|
10344
|
+
if ((0, import_node_fs20.existsSync)(state)) {
|
|
10093
10345
|
const saved = JSON.parse(readPrivate(state));
|
|
10094
10346
|
console.log(`Destinations: ${saved.destinations.length}/8${saved.destinations.length === 0 ? " (awaiting connection)" : ""}`);
|
|
10095
10347
|
for (const destination of saved.destinations) console.log(` ${destination.url}`);
|
|
@@ -10139,9 +10391,9 @@ Running version: ${health.body?.version ?? "unavailable"}`);
|
|
|
10139
10391
|
return 0;
|
|
10140
10392
|
}
|
|
10141
10393
|
if (command === "upgrade") {
|
|
10142
|
-
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.");
|
|
10143
10395
|
console.log("Staging upgrade\u2026");
|
|
10144
|
-
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";
|
|
10145
10397
|
const report = await upgradeInstallation({
|
|
10146
10398
|
root: ROOT,
|
|
10147
10399
|
dir,
|
|
@@ -10153,13 +10405,14 @@ Running version: ${health.body?.version ?? "unavailable"}`);
|
|
|
10153
10405
|
if (report.schemaVersion !== null) console.log(`Database schema: ${report.schemaVersion}`);
|
|
10154
10406
|
if (report.verification.health) console.log(`Health: ${report.verification.health.attempts} probe(s) in ${report.verification.health.elapsedMs}ms`);
|
|
10155
10407
|
else console.log("Health: skipped because the service was inactive; start it explicitly.");
|
|
10408
|
+
printMachineDataOutcome2(report.machineHistory);
|
|
10156
10409
|
return 0;
|
|
10157
10410
|
}
|
|
10158
10411
|
if (command === "rollback") {
|
|
10159
10412
|
console.log("Rolling back\u2026");
|
|
10160
10413
|
const report = await rollbackInstallation({
|
|
10161
10414
|
dir,
|
|
10162
|
-
backup: values.backup ? (0,
|
|
10415
|
+
backup: values.backup ? (0, import_node_path21.resolve)(values.backup) : void 0,
|
|
10163
10416
|
healthDeadlineMs: healthDeadline(values.timeout)
|
|
10164
10417
|
});
|
|
10165
10418
|
printSuccess(`Rolled back: rigscope ${report.version} (previous ${report.previousVersion}).`);
|
|
@@ -10177,7 +10430,7 @@ Running version: ${health.body?.version ?? "unavailable"}`);
|
|
|
10177
10430
|
if (!componentEnabled(config, "hub")) throw new Error("This installation has no hub component.");
|
|
10178
10431
|
const password = recoveryPassword;
|
|
10179
10432
|
const report = await recoverAdminPassword({
|
|
10180
|
-
database: (0,
|
|
10433
|
+
database: (0, import_node_path21.join)(dir, "hub", "telemetry.sqlite"),
|
|
10181
10434
|
username: values.user ?? "owner",
|
|
10182
10435
|
password,
|
|
10183
10436
|
enable: values.enable === true
|