fix: declare D601 HWLAB PK01 migration path

This commit is contained in:
Codex
2026-06-12 23:41:10 +00:00
parent 453b8abd2a
commit 4fe7ca0c73
3 changed files with 88 additions and 3 deletions
+80 -2
View File
@@ -117,6 +117,8 @@ export function hwlabNodeHelp(): Record<string, unknown> {
"bun scripts/cli.ts hwlab nodes control-plane refresh --node G14 --lane v03 --confirm",
"bun scripts/cli.ts hwlab nodes control-plane sync --node D601 --lane v03 --confirm",
"bun scripts/cli.ts hwlab nodes control-plane trigger-current --node G14 --lane v03 --confirm",
"bun scripts/cli.ts hwlab nodes control-plane runtime-migration --node D601 --lane v03 --dry-run",
"bun scripts/cli.ts hwlab nodes control-plane runtime-migration --node D601 --lane v03 --confirm",
"bun scripts/cli.ts hwlab nodes control-plane allow-endpoint-bridge --node G14 --lane v03 --confirm",
"bun scripts/cli.ts hwlab nodes git-mirror status --node G14 --lane v03",
"bun scripts/cli.ts hwlab nodes secret status --node G14 --lane v03 --name hwlab-v03-openfga",
@@ -142,7 +144,7 @@ async function runNodeDelegatedDomain(config: Config, domain: DelegatedNodeDomai
}
if (domain === "control-plane" && scoped.node !== defaultSpec.nodeId) {
if (scoped.action === "status") return nodeRuntimeControlPlaneStatus(scoped);
if (scoped.action === "apply" || scoped.action === "trigger-current" || scoped.action === "refresh" || scoped.action === "sync") {
if (scoped.action === "apply" || scoped.action === "trigger-current" || scoped.action === "refresh" || scoped.action === "sync" || scoped.action === "runtime-migration") {
if (scoped.confirm && !scoped.dryRun && !scoped.wait) return startNodeDelegatedJob(scoped);
return nodeRuntimeControlPlaneRun(scoped);
}
@@ -183,6 +185,7 @@ function parseNodeScopedDelegatedOptions(domain: DelegatedNodeDomain, args: stri
dryRun: boolean;
wait: boolean;
rerun: boolean;
allowLiveDbRead: boolean;
timeoutSeconds: number;
originalArgs: string[];
spec: HwlabRuntimeLaneSpec;
@@ -206,6 +209,7 @@ function parseNodeScopedDelegatedOptions(domain: DelegatedNodeDomain, args: stri
dryRun,
wait: args.includes("--wait"),
rerun: args.includes("--rerun"),
allowLiveDbRead: args.includes("--allow-live-db-read"),
timeoutSeconds: positiveIntegerOption(args, "--timeout-seconds", 1800, 3600),
originalArgs: [...args],
spec,
@@ -343,7 +347,7 @@ function nodeRuntimeUnsupportedAction(scoped: ReturnType<typeof parseNodeScopedD
lane: scoped.lane,
mutation: false,
degradedReason: "unsupported-node-scoped-runtime-action",
message: "node-scoped runtime currently supports plan/status/apply/refresh/sync/trigger-current",
message: "node-scoped runtime currently supports plan/status/apply/refresh/sync/trigger-current/runtime-migration",
expected: nodeRuntimeExpected(scoped.spec),
};
}
@@ -558,9 +562,83 @@ function nodeRuntimeControlPlaneRun(scoped: ReturnType<typeof parseNodeScopedDel
if (scoped.action === "sync") return nodeRuntimeSync(scoped);
if (scoped.action === "apply") return nodeRuntimeApply(scoped);
if (scoped.action === "trigger-current") return nodeRuntimeTriggerCurrent(scoped);
if (scoped.action === "runtime-migration") return nodeRuntimeMigration(scoped);
return nodeRuntimeUnsupportedAction(scoped);
}
function nodeRuntimeMigration(scoped: ReturnType<typeof parseNodeScopedDelegatedOptions>): Record<string, unknown> {
const spec = scoped.spec;
if (scoped.allowLiveDbRead && scoped.confirm) throw new Error("control-plane runtime-migration accepts --allow-live-db-read only with dry-run/source-check mode, not --confirm");
if (!scoped.confirm && !scoped.dryRun) throw new Error("control-plane runtime-migration requires --dry-run or --confirm");
const head = resolveNodeRuntimeLaneHead(spec);
const sourceCommit = head.sourceCommit;
if (sourceCommit === null) {
return {
ok: false,
command: `hwlab nodes control-plane runtime-migration --node ${scoped.node} --lane ${scoped.lane}`,
node: scoped.node,
lane: scoped.lane,
phase: "source-head",
mutation: false,
degradedReason: "node-runtime-source-head-unresolved",
headProbe: compactRuntimeCommand(head.result),
};
}
const reportPath = `/tmp/hwlab-${scoped.node.toLowerCase()}-${scoped.lane}-runtime-migration-${shortSha(sourceCommit)}.json`;
const migrationArgs = scoped.dryRun
? [
...(scoped.allowLiveDbRead ? ["--dry-run", "--allow-live-db-read", "--confirm-dev"] : ["--check"]),
"--report",
reportPath,
]
: [
"--apply",
"--confirm-dev",
"--confirmed-non-production",
"--report",
reportPath,
];
const result = runNodeK3sArgs(spec, [
"kubectl",
"exec",
"-n",
spec.runtimeNamespace,
"deployment/hwlab-cloud-api",
"-c",
"hwlab-cloud-api",
"--",
"sh",
"-lc",
`cd /workspace/hwlab-boot/repo && exec bun cmd/hwlab-cloud-api/migrate.ts ${migrationArgs.map(shellQuote).join(" ")}`,
], scoped.timeoutSeconds);
const ok = isCommandSuccess(result);
return {
ok,
command: `hwlab nodes control-plane runtime-migration --node ${scoped.node} --lane ${scoped.lane}`,
node: scoped.node,
lane: scoped.lane,
mode: scoped.dryRun ? scoped.allowLiveDbRead ? "live-read-dry-run" : "source-check" : "confirmed-apply",
sourceCommit,
runtimeNamespace: spec.runtimeNamespace,
target: "deployment/hwlab-cloud-api -c hwlab-cloud-api",
workingDirectory: "/workspace/hwlab-boot/repo",
migrationCommand: ["bun", "cmd/hwlab-cloud-api/migrate.ts", ...migrationArgs],
reportPath,
mutation: !scoped.dryRun && ok,
result: compactRuntimeCommand(result),
degradedReason: ok ? undefined : "node-runtime-migration-failed",
next: scoped.dryRun
? {
liveReadDryRun: `bun scripts/cli.ts hwlab nodes control-plane runtime-migration --node ${scoped.node} --lane ${scoped.lane} --allow-live-db-read --dry-run`,
apply: `bun scripts/cli.ts hwlab nodes control-plane runtime-migration --node ${scoped.node} --lane ${scoped.lane} --confirm`,
}
: {
health: `curl -fsS --max-time 20 ${spec.publicApiUrl}/health/live`,
status: `bun scripts/cli.ts hwlab nodes control-plane status --node ${scoped.node} --lane ${scoped.lane}`,
},
};
}
function nodeRuntimeApply(scoped: ReturnType<typeof parseNodeScopedDelegatedOptions>): Record<string, unknown> {
const spec = scoped.spec;
const head = resolveNodeRuntimeLaneHead(spec);