Add a graceful Shutdown action alongside Proxmox's Start/Restart/Stop
Stop maps to Proxmox's hard power-off (/status/stop) — fine for a
crashed guest, but risky for anything with a filesystem that'd rather
flush cleanly first. Proxmox exposes a separate /status/shutdown
endpoint that asks the guest to power itself down (ACPI event for a
VM, SIGTERM-then-wait for a container), so add it as its own action
rather than overloading Stop.
- New shutdownGuest() on the Proxmox adapter, calling /status/shutdown.
- The existing generic action route/loop already dispatches by
${action}Guest, so adding "shutdown" to that list was enough on the
server side — no new route needed.
- New Shutdown button next to Restart/Stop on both the Integrations
page's guest table and a Proxmox-linked server's detail page.
Stop's confirm prompt now explicitly points at Shutdown as the
gentler alternative.
Verified end-to-end against a mock Proxmox server: the shutdown call
hits /status/shutdown (never /status/stop) and is audit-logged as
shutdown_guest.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
de9b6a2d6a
commit
a6ab69316d
5 files changed
+23
-6
No files matched your search
@@ -62,6 +62,8 @@ export interface ProxmoxAdapter {
|
||||
startGuest(node: string, type: ProxmoxGuestType, vmid: number): Promise<void>;
|
||||
stopGuest(node: string, type: ProxmoxGuestType, vmid: number): Promise<void>;
|
||||
restartGuest(node: string, type: ProxmoxGuestType, vmid: number): Promise<void>;
|
||||
/** Graceful shutdown (ACPI power event for a VM, SIGTERM-then-wait for a container) — unlike stopGuest, this asks the guest OS to shut itself down. */
|
||||
shutdownGuest(node: string, type: ProxmoxGuestType, vmid: number): Promise<void>;
|
||||
}
|
||||
|
||||
function parseSizeToBytes(size: string): number | null {
|
||||
@@ -267,6 +269,7 @@ export function createProxmoxAdapter(config: ProxmoxConfig): ProxmoxAdapter {
|
||||
const startGuest = (node: string, type: ProxmoxGuestType, vmid: number) => statusAction(node, type, vmid, "start");
|
||||
const stopGuest = (node: string, type: ProxmoxGuestType, vmid: number) => statusAction(node, type, vmid, "stop");
|
||||
const restartGuest = (node: string, type: ProxmoxGuestType, vmid: number) => statusAction(node, type, vmid, "reboot");
|
||||
const shutdownGuest = (node: string, type: ProxmoxGuestType, vmid: number) => statusAction(node, type, vmid, "shutdown");
|
||||
|
||||
async function ping(): Promise<{ ok: boolean; latencyMs?: number; error?: string }> {
|
||||
const start = Date.now();
|
||||
@@ -278,5 +281,5 @@ export function createProxmoxAdapter(config: ProxmoxConfig): ProxmoxAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
return { ping, listGuests, getGuestDetail, startGuest, stopGuest, restartGuest };
|
||||
return { ping, listGuests, getGuestDetail, startGuest, stopGuest, restartGuest, shutdownGuest };
|
||||
}
|
||||
@@ -627,7 +627,7 @@ integrationsRouter.get("/:id/proxmox/guests", asyncHandler(async (req, res) => {
|
||||
}
|
||||
}));
|
||||
|
||||
const proxmoxActions = ["start", "stop", "restart"] as const;
|
||||
const proxmoxActions = ["start", "stop", "restart", "shutdown"] as const;
|
||||
|
||||
for (const action of proxmoxActions) {
|
||||
integrationsRouter.post(
|
||||
|
||||
Reference in new issue
Block a user