功能:完善云管助手与GPU故障恢复核对

这个提交包含在:
songyiming 于 2026-11-13 19:08:40 +08:00 提交
1 父节点 b6026f9759
当前提交 9f7b01e4db
42 个文件已更改
+3576 -120

没有与搜索条件相匹配的文件

+52
查看文件
@@ -140,6 +140,58 @@ func (s *Server) heartbeat(c *gin.Context) {
}
s.deviceJSON(c, 200, gin.H{"accepted": true, "serverTime": time.Now().UTC()})
}
// appendTerminalLogs accepts small log batches from an online terminal. It is
// deliberately separate from collect-logs: agents can stream useful events
// during normal operation without creating a management task for every batch.
func (s *Server) appendTerminalLogs(c *gin.Context) {
var in struct {
BootID string `json:"bootId" binding:"max=120"`
Entries []struct {
CapturedAt string `json:"capturedAt"`
Level string `json:"level" binding:"omitempty,oneof=debug info warn error"`
Message string `json:"message" binding:"required,max=16000"`
} `json:"entries" binding:"required,min=1,max=100"`
}
if !s.decode(c, &in) {
return
}
if len(in.Entries) == 0 {
s.fail(c, 400, "invalid_logs", "日志批次不能为空")
return
}
if len(in.BootID) > 120 || strings.IndexByte(in.BootID, 0) >= 0 {
s.fail(c, 400, "invalid_logs", "日志启动标识无效")
return
}
tx := deviceTx(c)
for _, entry := range in.Entries {
message := redactDiagnostic(strings.TrimSpace(entry.Message))
if message == "" || len(message) > 16000 {
s.fail(c, 400, "invalid_logs", "日志内容不能为空或超出长度限制")
return
}
capturedAt := time.Now().UTC()
if strings.TrimSpace(entry.CapturedAt) != "" {
parsed, err := time.Parse(time.RFC3339Nano, entry.CapturedAt)
if err != nil || parsed.After(time.Now().Add(2*time.Minute)) || parsed.Before(time.Now().Add(-10*time.Minute)) {
s.fail(c, 400, "invalid_logs", "日志时间必须是最近 10 分钟内的 RFC3339 时间")
return
}
capturedAt = parsed.UTC()
}
level := strings.TrimSpace(entry.Level)
if level == "" {
level = "info"
}
if _, err := tx.ExecContext(c.Request.Context(), `INSERT INTO terminal_log_entries(id,terminal_id,captured_at,boot_id,level,message) VALUES($1,$2,$3,$4,$5,$6)`, store.ID("log_"), c.GetString("terminalId"), capturedAt, redactDiagnostic(in.BootID), level, message); err != nil {
s.dbError(c, err)
return
}
}
_, _ = tx.ExecContext(c.Request.Context(), "UPDATE terminals SET last_seen=now(),status='online' WHERE id=$1", c.GetString("terminalId"))
s.deviceJSON(c, 202, gin.H{"accepted": len(in.Entries), "serverTime": time.Now().UTC()})
}
func (s *Server) deviceConfig(c *gin.Context) {
var version int
if err := deviceTx(c).GetContext(c.Request.Context(), &version, "SELECT config_version FROM terminals WHERE id=$1", c.GetString("terminalId")); err != nil {