F1 告警静默规则 [done]: - 后端 alert_silence.go: CRUD + Toggle (onetime/daily/weekly 三模式) - 告警引擎 isSilenced 集成 (alert_engine.go) - 前端 SilenceRuleTab + SilenceDialog - 路由 /alerts/silences 已注册 F2 审计日志导出 [done]: - 重写 ExportAuditLogs: 真正的 CSV 导出 (encoding/csv + UTF-8 BOM) - 支持 module/action/username/startTime/endTime 筛选 - 导出限制 10000 条防溢出,自动记录审计日志 - JSON 格式向后兼容 (format=json) - 前端 exportLogs 传递查询参数 同时包含累积的前期工作: - 目录重构 internal/ -> controller/model/router (v0.55-v0.57) - 后端分层架构 dto/repository/service/utils - 审计模块全功能 (终端审计/操作审计/登录日志) - asciicast v2 录制格式 - SFTP 文件浏览器 - StatStrip 紧凑统计条 - 在线会话自动刷新 - LiveMonitor WebSocket 诊断修复 验证: go build ✅ | npm run build ✅ | Docker 部署 ✅ | 10 回归端点 ✅ | CSV 导出 ✅ | 静默 CRUD ✅
77 lines
2.1 KiB
Go
77 lines
2.1 KiB
Go
package controller
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"crypto/rand"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"os/exec"
|
|
"time"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// randomCode returns a short unique code for records that require a unique
|
|
// string identifier (e.g. playbooks). It combines a unix timestamp with 4
|
|
// random hex bytes to guarantee uniqueness even under rapid sequential inserts.
|
|
func randomCode(prefix string) string {
|
|
b := make([]byte, 4)
|
|
_, _ = rand.Read(b)
|
|
return fmt.Sprintf("%s-%d-%s", prefix, time.Now().Unix(), hex.EncodeToString(b))
|
|
}
|
|
|
|
// runLocal executes a script or shell command locally on the AIOps host and
|
|
// returns the combined stdout+stderr output, the process exit code (0 = success)
|
|
// and the wall-clock duration in milliseconds. A timeout prevents runaway jobs.
|
|
func runLocal(scriptType, content string, timeoutSec int) (output string, exitCode int, durationMs int) {
|
|
start := time.Now()
|
|
timeout := time.Duration(timeoutSec) * time.Second
|
|
if timeout <= 0 {
|
|
timeout = 300 * time.Second
|
|
}
|
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
|
defer cancel()
|
|
|
|
var cmd *exec.Cmd
|
|
switch scriptType {
|
|
case "python":
|
|
cmd = exec.CommandContext(ctx, "python3", "-c", content)
|
|
default: // shell / command / "" → run via bash
|
|
cmd = exec.CommandContext(ctx, "bash", "-c", content)
|
|
}
|
|
|
|
var out bytes.Buffer
|
|
cmd.Stdout = &out
|
|
cmd.Stderr = &out
|
|
|
|
err := cmd.Run()
|
|
durationMs = int(time.Since(start).Milliseconds())
|
|
output = out.String()
|
|
|
|
if ctx.Err() == context.DeadlineExceeded {
|
|
output += fmt.Sprintf("\n[超时] 执行超过 %d 秒被终止", timeoutSec)
|
|
return output, -1, durationMs
|
|
}
|
|
if err != nil {
|
|
if exitError, ok := err.(*exec.ExitError); ok {
|
|
exitCode = exitError.ExitCode()
|
|
} else {
|
|
exitCode = -1
|
|
output += "\n" + err.Error()
|
|
}
|
|
return output, exitCode, durationMs
|
|
}
|
|
return output, 0, durationMs
|
|
}
|
|
|
|
// AutomationHandler 自动化运维处理器
|
|
type AutomationHandler struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
// NewAutomationHandler 创建自动化运维处理器
|
|
func NewAutomationHandler(db *gorm.DB) *AutomationHandler {
|
|
return &AutomationHandler{db: db}
|
|
}
|