mirror of
https://github.com/moltbot/moltbot.git
synced 2026-04-23 14:45:46 +00:00
refactor(daemon): share systemd service action flow
This commit is contained in:
@@ -11,7 +11,9 @@ import { parseSystemdExecStart } from "./systemd-unit.js";
|
||||
import {
|
||||
isSystemdUserServiceAvailable,
|
||||
parseSystemdShow,
|
||||
restartSystemdService,
|
||||
resolveSystemdUserUnitPath,
|
||||
stopSystemdService,
|
||||
} from "./systemd.js";
|
||||
|
||||
describe("systemd availability", () => {
|
||||
@@ -151,3 +153,58 @@ describe("parseSystemdExecStart", () => {
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("systemd service control", () => {
|
||||
beforeEach(() => {
|
||||
execFileMock.mockReset();
|
||||
});
|
||||
|
||||
it("stops the resolved user unit", async () => {
|
||||
execFileMock
|
||||
.mockImplementationOnce((_cmd, _args, _opts, cb) => cb(null, "", ""))
|
||||
.mockImplementationOnce((_cmd, args, _opts, cb) => {
|
||||
expect(args).toEqual(["--user", "stop", "openclaw-gateway.service"]);
|
||||
cb(null, "", "");
|
||||
});
|
||||
const write = vi.fn();
|
||||
const stdout = { write } as unknown as NodeJS.WritableStream;
|
||||
|
||||
await stopSystemdService({ stdout, env: {} });
|
||||
|
||||
expect(write).toHaveBeenCalledTimes(1);
|
||||
expect(String(write.mock.calls[0]?.[0])).toContain("Stopped systemd service");
|
||||
});
|
||||
|
||||
it("restarts a profile-specific user unit", async () => {
|
||||
execFileMock
|
||||
.mockImplementationOnce((_cmd, _args, _opts, cb) => cb(null, "", ""))
|
||||
.mockImplementationOnce((_cmd, args, _opts, cb) => {
|
||||
expect(args).toEqual(["--user", "restart", "openclaw-gateway-work.service"]);
|
||||
cb(null, "", "");
|
||||
});
|
||||
const write = vi.fn();
|
||||
const stdout = { write } as unknown as NodeJS.WritableStream;
|
||||
|
||||
await restartSystemdService({ stdout, env: { OPENCLAW_PROFILE: "work" } });
|
||||
|
||||
expect(write).toHaveBeenCalledTimes(1);
|
||||
expect(String(write.mock.calls[0]?.[0])).toContain("Restarted systemd service");
|
||||
});
|
||||
|
||||
it("surfaces stop failures with systemctl detail", async () => {
|
||||
execFileMock
|
||||
.mockImplementationOnce((_cmd, _args, _opts, cb) => cb(null, "", ""))
|
||||
.mockImplementationOnce((_cmd, _args, _opts, cb) => {
|
||||
const err = new Error("stop failed") as Error & { code?: number };
|
||||
err.code = 1;
|
||||
cb(err, "", "permission denied");
|
||||
});
|
||||
|
||||
await expect(
|
||||
stopSystemdService({
|
||||
stdout: { write: vi.fn() } as unknown as NodeJS.WritableStream,
|
||||
env: {},
|
||||
}),
|
||||
).rejects.toThrow("systemctl stop failed: permission denied");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -253,6 +253,22 @@ export async function uninstallSystemdService({
|
||||
}
|
||||
}
|
||||
|
||||
async function runSystemdServiceAction(params: {
|
||||
stdout: NodeJS.WritableStream;
|
||||
env?: Record<string, string | undefined>;
|
||||
action: "stop" | "restart";
|
||||
label: string;
|
||||
}) {
|
||||
await assertSystemdAvailable();
|
||||
const serviceName = resolveSystemdServiceName(params.env ?? {});
|
||||
const unitName = `${serviceName}.service`;
|
||||
const res = await execSystemctl(["--user", params.action, unitName]);
|
||||
if (res.code !== 0) {
|
||||
throw new Error(`systemctl ${params.action} failed: ${res.stderr || res.stdout}`.trim());
|
||||
}
|
||||
params.stdout.write(`${formatLine(params.label, unitName)}\n`);
|
||||
}
|
||||
|
||||
export async function stopSystemdService({
|
||||
stdout,
|
||||
env,
|
||||
@@ -260,14 +276,12 @@ export async function stopSystemdService({
|
||||
stdout: NodeJS.WritableStream;
|
||||
env?: Record<string, string | undefined>;
|
||||
}): Promise<void> {
|
||||
await assertSystemdAvailable();
|
||||
const serviceName = resolveSystemdServiceName(env ?? {});
|
||||
const unitName = `${serviceName}.service`;
|
||||
const res = await execSystemctl(["--user", "stop", unitName]);
|
||||
if (res.code !== 0) {
|
||||
throw new Error(`systemctl stop failed: ${res.stderr || res.stdout}`.trim());
|
||||
}
|
||||
stdout.write(`${formatLine("Stopped systemd service", unitName)}\n`);
|
||||
await runSystemdServiceAction({
|
||||
stdout,
|
||||
env,
|
||||
action: "stop",
|
||||
label: "Stopped systemd service",
|
||||
});
|
||||
}
|
||||
|
||||
export async function restartSystemdService({
|
||||
@@ -277,14 +291,12 @@ export async function restartSystemdService({
|
||||
stdout: NodeJS.WritableStream;
|
||||
env?: Record<string, string | undefined>;
|
||||
}): Promise<void> {
|
||||
await assertSystemdAvailable();
|
||||
const serviceName = resolveSystemdServiceName(env ?? {});
|
||||
const unitName = `${serviceName}.service`;
|
||||
const res = await execSystemctl(["--user", "restart", unitName]);
|
||||
if (res.code !== 0) {
|
||||
throw new Error(`systemctl restart failed: ${res.stderr || res.stdout}`.trim());
|
||||
}
|
||||
stdout.write(`${formatLine("Restarted systemd service", unitName)}\n`);
|
||||
await runSystemdServiceAction({
|
||||
stdout,
|
||||
env,
|
||||
action: "restart",
|
||||
label: "Restarted systemd service",
|
||||
});
|
||||
}
|
||||
|
||||
export async function isSystemdServiceEnabled(args: {
|
||||
|
||||
Reference in New Issue
Block a user