功能:完善通用云管工作台、审计与诊断能力
This commit is contained in:
1 parent
5ac692724d
commit
9f05aa20ea
225 files changed
+14266
-141
No files matched your search
@@ -3,6 +3,7 @@ package server
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -42,7 +43,7 @@ func (s *Server) settings(c *gin.Context) {
|
||||
if pve != nil {
|
||||
provider = "proxmox"
|
||||
}
|
||||
c.JSON(200, gin.H{"mode": s.Config.Mode, "computeProvider": provider, "pveConfigured": pve != nil, "terminalTransport": "https-poll", "capabilities": []string{"terminal-system-metrics", "gpu-inventory", "desktop-batches", "desktop-snapshots", "pve-connection", "desktop-hardware", "login-rate-limit", "csv-imports", "session-history", "monitor-alerts", "administrators", "password", "auth", "resources", "desktops", "templates", "pools", "clone", "desktop-connection", "terminals", "terminal-lifecycle", "terminal-policies", "users", "batch-bindings", "bindings", "tasks", "audit"}})
|
||||
c.JSON(200, gin.H{"mode": s.Config.Mode, "computeProvider": provider, "pveConfigured": pve != nil, "terminalTransport": "https-poll", "capabilities": []string{"diagnostics-center", "admin-mfa", "administrator-sessions", "task-history", "audit-query-export", "terminal-metric-alerts", "terminal-system-metrics", "gpu-inventory", "desktop-batches", "desktop-snapshots", "pve-connection", "desktop-hardware", "login-rate-limit", "csv-imports", "session-history", "monitor-alerts", "administrators", "password", "auth", "resources", "desktops", "templates", "pools", "clone", "desktop-connection", "terminals", "terminal-lifecycle", "terminal-policies", "users", "batch-bindings", "bindings", "tasks", "audit"}})
|
||||
}
|
||||
func (s *Server) resources(c *gin.Context) {
|
||||
items := []model.Resource{}
|
||||
@@ -195,14 +196,6 @@ func (s *Server) bindings(c *gin.Context) {
|
||||
}
|
||||
c.JSON(200, user)
|
||||
}
|
||||
func (s *Server) tasks(c *gin.Context) {
|
||||
items := []model.Task{}
|
||||
if err := s.DB.SelectContext(c.Request.Context(), &items, "SELECT * FROM tasks ORDER BY created_at DESC LIMIT 1000"); err != nil {
|
||||
s.dbError(c, err)
|
||||
return
|
||||
}
|
||||
list(c, items)
|
||||
}
|
||||
func (s *Server) task(c *gin.Context) {
|
||||
var t model.Task
|
||||
if err := s.DB.GetContext(c.Request.Context(), &t, "SELECT * FROM tasks WHERE id=$1", c.Param("id")); err != nil {
|
||||
@@ -211,14 +204,6 @@ func (s *Server) task(c *gin.Context) {
|
||||
}
|
||||
c.JSON(200, t)
|
||||
}
|
||||
func (s *Server) audits(c *gin.Context) {
|
||||
items := []model.Audit{}
|
||||
if err := s.DB.SelectContext(c.Request.Context(), &items, "SELECT * FROM audit_logs ORDER BY created_at DESC LIMIT 1000"); err != nil {
|
||||
s.dbError(c, err)
|
||||
return
|
||||
}
|
||||
list(c, items)
|
||||
}
|
||||
func (s *Server) discoverVMs(c *gin.Context) {
|
||||
pve := s.currentPVE()
|
||||
if pve == nil {
|
||||
@@ -322,6 +307,10 @@ func (s *Server) desktopAction(c *gin.Context) {
|
||||
s.fail(c, 503, "pve_unconfigured", "Proxmox 尚未配置")
|
||||
return
|
||||
}
|
||||
if s.exclusiveGPU(d) && in.Action != "shutdown" {
|
||||
s.fail(c, 409, "exclusive_gpu_power", "此桌面共用显卡,请先退出当前云桌面,再从终端选择页启动")
|
||||
return
|
||||
}
|
||||
unresolved, err := maintenanceBlocked(c.Request.Context(), s.DB, d.ID, "", false)
|
||||
if err != nil {
|
||||
s.dbError(c, err)
|
||||
@@ -376,11 +365,15 @@ func (s *Server) submitTask(c *gin.Context, kind, action, targetID, targetName s
|
||||
}
|
||||
defer tx.Rollback()
|
||||
if kind == "desktop" {
|
||||
var id string
|
||||
if err = tx.GetContext(ctx, &id, "SELECT id FROM desktops WHERE id=$1 FOR UPDATE", targetID); err != nil {
|
||||
var desktop model.Desktop
|
||||
if err = tx.GetContext(ctx, &desktop, "SELECT * FROM desktops WHERE id=$1 FOR UPDATE", targetID); err != nil {
|
||||
s.dbError(c, err)
|
||||
return
|
||||
}
|
||||
if err = s.exclusiveGPUMaintenance(ctx, tx, desktop); err != nil {
|
||||
s.fail(c, 409, "gpu_switch_busy", err.Error())
|
||||
return
|
||||
}
|
||||
unresolved, err := maintenanceBlocked(ctx, tx, targetID, "", false)
|
||||
if err != nil {
|
||||
s.dbError(c, err)
|
||||
@@ -541,8 +534,17 @@ func (s *Server) RunWorker(ctx context.Context) {
|
||||
}
|
||||
// Unknown outcomes are never automatically retried after a worker restart.
|
||||
var expired []model.Task
|
||||
if s.DB.SelectContext(ctx, &expired, "SELECT * FROM tasks WHERE status IN ('queued','running') AND ((kind NOT IN ('provision','hardware','snapshot','batch-desktop') AND created_at<now()-interval '2 minutes') OR (kind='batch-desktop' AND ((status='queued' AND created_at<now()-interval '2 hours') OR (status='running' AND updated_at<now()-interval '2 minutes'))) OR (kind IN ('provision','hardware','snapshot') AND updated_at<now()-interval '35 minutes'))") == nil {
|
||||
if s.DB.SelectContext(ctx, &expired, "SELECT * FROM tasks WHERE status IN ('queued','running') AND ((kind NOT IN ('provision','hardware','snapshot','batch-desktop','gpu-prepare') AND created_at<now()-interval '2 minutes') OR (kind='gpu-prepare' AND created_at<now()-interval '5 minutes') OR (kind='batch-desktop' AND ((status='queued' AND created_at<now()-interval '2 hours') OR (status='running' AND updated_at<now()-interval '2 minutes'))) OR (kind IN ('provision','hardware','snapshot') AND updated_at<now()-interval '35 minutes'))") == nil {
|
||||
for _, t := range expired {
|
||||
if t.Kind == "gpu-prepare" {
|
||||
var state gpuPrepareState
|
||||
status := "timeout"
|
||||
if json.Unmarshal([]byte(t.ProviderRef), &state) == nil && state.Phase == "queued" {
|
||||
status = "failed"
|
||||
}
|
||||
_ = s.complete(ctx, t, status, "桌面准备超时,请核对任务和实际电源状态;不会自动重放")
|
||||
continue
|
||||
}
|
||||
if t.Kind == "batch-desktop" {
|
||||
s.finishBatchPower(t, "", "expired", "")
|
||||
continue
|
||||
@@ -562,11 +564,11 @@ func (s *Server) RunWorker(ctx context.Context) {
|
||||
}
|
||||
}
|
||||
var t model.Task
|
||||
err := s.DB.GetContext(ctx, &t, `UPDATE tasks SET status='running',updated_at=now(),message='正在执行,等待最终回执' WHERE id=(SELECT id FROM tasks WHERE ((status='queued' AND kind!='terminal') OR (kind='provision' AND status='running' AND provider_ref!='') OR (kind IN ('hardware','snapshot','batch-desktop') AND status='running')) AND ($1 OR kind NOT IN ('provision','hardware','snapshot','batch-desktop')) ORDER BY created_at FOR UPDATE SKIP LOCKED LIMIT 1) RETURNING *`, !provisionBusy)
|
||||
err := s.DB.GetContext(ctx, &t, `UPDATE tasks SET status='running',updated_at=now(),message='正在执行,等待最终回执' WHERE id=(SELECT id FROM tasks WHERE ((status='queued' AND kind!='terminal') OR (kind='provision' AND status='running' AND provider_ref!='') OR (kind IN ('hardware','snapshot','batch-desktop') AND status='running')) AND ($1 OR kind NOT IN ('provision','hardware','snapshot','batch-desktop','gpu-prepare')) ORDER BY created_at FOR UPDATE SKIP LOCKED LIMIT 1) RETURNING *`, !provisionBusy)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if t.Kind == "provision" || t.Kind == "hardware" || t.Kind == "snapshot" || t.Kind == "batch-desktop" {
|
||||
if t.Kind == "provision" || t.Kind == "hardware" || t.Kind == "snapshot" || t.Kind == "batch-desktop" || t.Kind == "gpu-prepare" {
|
||||
provisionBusy = true
|
||||
go func(task model.Task) { s.execute(workerCtx, task); provisionDone <- struct{}{} }(t)
|
||||
} else {
|
||||
@@ -594,6 +596,10 @@ func (s *Server) RunSync(ctx context.Context) {
|
||||
}
|
||||
}
|
||||
func (s *Server) execute(parent context.Context, t model.Task) {
|
||||
if t.Kind == "gpu-prepare" {
|
||||
s.executeGPUPrepare(parent, t)
|
||||
return
|
||||
}
|
||||
if t.Kind == "batch-desktop" {
|
||||
s.executeBatchPower(parent, t)
|
||||
return
|
||||
|
||||
Reference in new issue
Block a user