-
Notifications
You must be signed in to change notification settings - Fork 3k
Expand file tree
/
Copy pathdoctor-lifecycle-registration.ts
More file actions
83 lines (76 loc) · 3.15 KB
/
Copy pathdoctor-lifecycle-registration.ts
File metadata and controls
83 lines (76 loc) · 3.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
import {
collectLifecycleRegistrationIssues,
type LifecycleRegistrationIssue,
} from "../../domain/lifecycle-registration";
import { inspectPortableRuntimeReceiptReadiness } from "../../onboard/experimental/portable-runtime-receipt-readiness";
import type { SandboxEntry } from "../../state/registry";
import type { DoctorCheck } from "./doctor-report";
function uniqueOrdered<T extends string>(values: readonly T[]): T[] {
return values.filter((value, index) => values.indexOf(value) === index);
}
function formatFieldList(
issues: readonly LifecycleRegistrationIssue[],
reason: LifecycleRegistrationIssue["reason"],
): string {
return uniqueOrdered(
issues.filter((issue) => issue.reason === reason).map((issue) => issue.field),
)
.sort()
.join(", ");
}
export function buildPortableRuntimeCheck(sandboxName: string): DoctorCheck | null {
const portable = inspectPortableRuntimeReceiptReadiness(sandboxName);
if (!portable) return null;
const recordedSocket = !portable.ok && portable.socketPath
? ` Recorded socket: ${portable.socketPath}.`
: "";
return portable.ok
? {
group: "Host",
label: "Portable Podman API",
status: "ok",
detail: `server ${portable.serverVersion}; ${portable.timing.mode}; activation ${String(portable.timing.activationMs)} ms; API ${String(portable.timing.apiMs)} ms; total ${String(portable.timing.totalMs)} ms`,
}
: {
group: "Host",
label: "Portable Podman API",
status: "fail",
detail: `${portable.stage}: ${portable.detail}${recordedSocket}`,
hint: "repair the recorded current-user Podman endpoint, then retry",
};
}
export function buildLifecycleRegistrationCheck(
sandboxName: string,
entry: SandboxEntry,
cliName: string,
options: { dashboardPortRequired?: boolean } = {},
): DoctorCheck {
const issues = collectLifecycleRegistrationIssues(entry, {
dashboardPortRequired: options.dashboardPortRequired !== false,
});
if (issues.length === 0) {
return {
group: "Sandbox",
label: "Lifecycle registration",
status: "ok",
detail:
"registry entry has lifecycle metadata for snapshot, rebuild, upgrade, recovery, and reboot",
};
}
const affectedOperations = uniqueOrdered(issues.flatMap((issue) => issue.operations)).sort();
const missingFields = formatFieldList(issues, "missing");
const invalidFields = formatFieldList(issues, "invalid");
const fieldParts = [
missingFields ? `missing ${missingFields}` : null,
invalidFields ? `invalid ${invalidFields}` : null,
].filter((part): part is string => part !== null);
return {
group: "Sandbox",
label: "Lifecycle registration",
status: "warn",
detail: `registry entry incomplete for lifecycle operations (${fieldParts.join("; ")}; affected: ${affectedOperations.join(", ")})`,
hint: `re-register or re-onboard '${sandboxName}' before running lifecycle commands such as \`${cliName} ${sandboxName} snapshot create\` or \`${cliName} ${sandboxName} rebuild\``,
};
}