Add Proxmox integration
Fifth live integration: VM/LXC status across every online node in the
cluster, with start/stop/restart actions — matching the "dashboard + basic
actions" depth from the plan. Adapter built against Proxmox VE's own
published API tree (pve.proxmox.com/pve-docs/api-viewer/apidoc.js — parsed
its ~4MB ExtJS tree structure directly since it's not plain JSON) plus
community-verified docs for the token auth header format, since the user's
instance isn't reachable from here.
server/src/integrations/proxmox/adapter.ts: GET /nodes for online nodes,
then GET /nodes/{node}/{qemu,lxc} per node in parallel (Promise.all) and
flattened, tagging each guest with its node and type; POST
/nodes/{node}/{qemu,lxc}/{vmid}/status/{start,stop,reboot} for actions (all
confirmed token-auth-eligible via the spec's "allowtoken" flag). Uses
node:https directly (like the cPanel DNS adapter) rather than fetch, since
Proxmox commonly runs a self-signed certificate in homelab setups — added
an "Allow self-signed certificate" checkbox field for that. Auth is
`Authorization: PVEAPIToken=<tokenId>=<tokenSecret>`, a different shape
from the other three integrations' single bearer token, so the field
schema splits it into two fields (a non-secret token ID like
"root@pam!homelab-manager" and a secret token value).
Verified: full build passes. Unreachable from here, so ran a 16-check HTTP
test against the live server: role gating, credential non-leakage,
disabled-integration blocking, invalid-guest-type and non-numeric-vmid
rejection, checkbox-only config correctly still failing required-field
validation, and the wrong_type crash-safety check for this fifth adapter
type — server stays up throughout. Real node/VM data and the actual
start/stop/restart actions still need verification once this app can reach
the user's Proxmox cluster.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
257ec3ec0a
commit
bc72b9e152
7 files changed
+454
-1
No files matched your search
@@ -271,6 +271,25 @@ export interface SemaphoreTemplatesResponse {
|
||||
summary: { total: number; failing: number };
|
||||
}
|
||||
|
||||
export type ProxmoxGuestType = "qemu" | "lxc";
|
||||
|
||||
export interface ProxmoxGuest {
|
||||
vmid: number;
|
||||
name: string;
|
||||
node: string;
|
||||
type: ProxmoxGuestType;
|
||||
status: string;
|
||||
cpu: number | null;
|
||||
maxmem: number | null;
|
||||
mem: number | null;
|
||||
uptime: number | null;
|
||||
}
|
||||
|
||||
export interface ProxmoxGuestsResponse {
|
||||
guests: ProxmoxGuest[];
|
||||
summary: { total: number; running: number };
|
||||
}
|
||||
|
||||
export class UnauthorizedError extends Error {}
|
||||
export class ForbiddenError extends Error {}
|
||||
|
||||
@@ -477,5 +496,14 @@ export const api = {
|
||||
{ method: "POST" },
|
||||
),
|
||||
},
|
||||
proxmox: {
|
||||
guests: (integrationId: number) => request<ProxmoxGuestsResponse>(`/api/integrations/${integrationId}/proxmox/guests`),
|
||||
start: (integrationId: number, node: string, type: ProxmoxGuestType, vmid: number) =>
|
||||
request<void>(`/api/integrations/${integrationId}/proxmox/nodes/${node}/${type}/${vmid}/start`, { method: "POST" }),
|
||||
stop: (integrationId: number, node: string, type: ProxmoxGuestType, vmid: number) =>
|
||||
request<void>(`/api/integrations/${integrationId}/proxmox/nodes/${node}/${type}/${vmid}/stop`, { method: "POST" }),
|
||||
restart: (integrationId: number, node: string, type: ProxmoxGuestType, vmid: number) =>
|
||||
request<void>(`/api/integrations/${integrationId}/proxmox/nodes/${node}/${type}/${vmid}/restart`, { method: "POST" }),
|
||||
},
|
||||
},
|
||||
};
|
||||
Reference in new issue
Block a user