feat(post-install): identity_network reboote et rebascule l'IP en BDD (tâche 4)

- updateMachine accepte name/hostname/port (correction d'identité réseau)
- rebootAndRebind : reboot sur l'ancienne connexion → attente du retour sur la
  NOUVELLE IP (verifyReboot avec host cible) → maj BDD (hostname + nom) si OK.
  Sécurité : BDD inchangée si la machine ne revient pas (récupération console/backups)
- execute post_install : si identity_network + reboot coché + succès, déclenche
  rebootAndRebind et joint le RebootResult ; statut error si reconnexion échoue

tsc 0 · 113 tests · build OK.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-06 19:12:39 +02:00
parent 3ea2e66359
commit 1530409d3b
3 changed files with 77 additions and 7 deletions
+49 -2
View File
@@ -1,9 +1,10 @@
// server/services/postInstall.ts
import { getMachineRow, getCreds } from "./machines.js";
import { getMachineRow, getCreds, updateMachine } from "./machines.js";
import { renderTemplate, type TemplateVars } from "../templates/render.js";
import { runScriptSudo } from "../ssh/client.js";
import { outputHub } from "../ws/outputHub.js";
import type { PostInstallResult, SnapshotError } from "@shared/types.js";
import { parseBootIdBefore, verifyReboot } from "./rebootVerify.js";
import type { PostInstallResult, RebootResult, SnapshotError } from "@shared/types.js";
// ----------------------------------------------------------------------------
// Manifestes de profils (registre versionné en code ; templates versionnés sur disque).
@@ -319,3 +320,49 @@ export async function runPostInstall(
const failed = (result.errors?.length ?? 0) > 0 || (/===SU:EXIT=\d+===/.test(raw) && !/===SU:EXIT=0===/.test(raw));
return { result, raw, status: failed ? "error" : "ok" };
}
/**
* Reboote la machine puis attend son retour sur la NOUVELLE IP, et corrige la BDD
* (hostname SSH + nom) si la reconnexion réussit. Sécurité : si la machine ne revient
* pas sur la nouvelle IP, la BDD n'est PAS modifiée (récupération via console + backups).
*/
export async function rebootAndRebind(
machineId: string,
newHost: string,
newName: string | null,
onData?: (c: string) => void,
): Promise<RebootResult> {
const m = getMachineRow(machineId);
if (!m) throw new Error("Machine introuvable");
const creds = getCreds(m);
// 1) Reboot sur l'ancienne connexion (capture boot_id avant).
let raw = "";
try {
const res = await runScriptSudo(creds, renderTemplate("apt/reboot.sh.tpl", {}), (c) => {
raw += c;
onData?.(c);
outputHub.publish(machineId, c);
}, 0);
raw = res.stdout;
} catch {
/* la connexion tombe pendant le reboot : normal */
}
const beforeBootId = parseBootIdBefore(raw);
outputHub.publish(machineId, `\n[reboot] attente du retour sur ${newHost}...\n`);
// 2) Reconnexion sur la NOUVELLE IP.
const reboot = await verifyReboot({ ...creds, hostname: newHost }, {
beforeBootId,
requestedAt: new Date().toISOString(),
});
// 3) Bascule BDD uniquement si la machine est bien revenue sur la nouvelle IP.
if (reboot.status === "ok") {
updateMachine(machineId, { hostname: newHost, ...(newName ? { name: newName } : {}) });
outputHub.publish(machineId, `\n[reboot] machine basculée sur ${newHost}, BDD mise à jour.\n`);
} else {
outputHub.publish(machineId, `\n[reboot] reconnexion ${newHost} échouée (${reboot.status}) — BDD inchangée.\n`);
}
return reboot;
}