feat: VM/CT Start/Stop im Frontend + Agent proxmox_action Handler

- Agent: neuer 'proxmox_action' Command (start/stop/shutdown fuer VMs und LXC)
- Backend: POST /api/v1/agents/{id}/proxmox/action Endpoint
- Frontend: Start/Stop/Shutdown Buttons in VMs- und Container-Tab
  - Play (gruen) = starten (nur wenn gestoppt)
  - Power (gelb) = Graceful Shutdown (nur VMs, nur wenn running)
  - Stop (rot) = Hard Stop (wenn running)
- api/client.js: proxmoxAction() Methode
This commit is contained in:
cynfo3000
2026-03-09 20:22:45 +01:00
parent 4cd9764cec
commit 291d2e3c17
4 changed files with 204 additions and 11 deletions
+31
View File
@@ -37,6 +37,7 @@ func (h *Handler) setupTunnelRoutes(mux *http.ServeMux, hub *ws.Hub) {
mux.HandleFunc("DELETE /api/v1/agents/{id}/wireguard/peers/{uuid}", h.wgDeletePeer(hub))
// Backup-Endpoints
mux.HandleFunc("POST /api/v1/agents/{id}/proxmox/action", h.proxmoxAction(hub))
mux.HandleFunc("POST /api/v1/agents/{id}/backup", h.triggerBackup(hub))
mux.HandleFunc("GET /api/v1/agents/{id}/backups", h.listBackups())
mux.HandleFunc("GET /api/v1/agents/{id}/backups/{backup_id}", h.getBackup())
@@ -265,6 +266,36 @@ func (h *Handler) agentReboot(hub *ws.Hub) http.HandlerFunc {
}
}
// proxmoxAction: VM/CT starten oder stoppen
func (h *Handler) proxmoxAction(hub *ws.Hub) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
agentID := r.PathValue("id")
var req struct {
Type string `json:"type"` // "vm" oder "ct"
VMID int `json:"vmid"`
Action string `json:"action"` // "start", "stop", "shutdown"
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
writeError(w, http.StatusBadRequest, "Ungültiger Request-Body")
return
}
if req.VMID <= 0 || req.Type == "" || req.Action == "" {
writeError(w, http.StatusBadRequest, "type, vmid und action erforderlich")
return
}
params := map[string]interface{}{
"type": req.Type,
"vmid": float64(req.VMID),
"action": req.Action,
}
h.auditLog(r, "proxmox_action", "agent", agentID, "", fmt.Sprintf("%s %s %d", req.Action, req.Type, req.VMID))
h.sendCommandAndWait(hub, agentID, "proxmox_action", params, 60, w)
}
}
// sendAgentCommand erstellt einen einfachen Command-Handler ohne Request-Body
func (h *Handler) sendAgentCommand(hub *ws.Hub, command string, params map[string]interface{}, timeoutSec int) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {