- CronJobManager: 编辑按钮接通 onClick → openEdit(job),弹出编辑对话框预填数据,
复用新建/编辑共用 Dialog(editingId 区分模式),标题/按钮文案动态切换,
保存时根据 editingId 调用 createJob 或 updateJob — 消除占位按钮
- ApprovalFlow: 修复 API 方法名不匹配导致 tsc -b 编译失败
(getInstances→getProcesses, getMyApprovals→getProcesses({status:'pending'}),
approveInstance→approveProcess, rejectInstance→rejectProcess)
+ 添加 ApprovalFlowManager 导出别名兼容 App.tsx 导入
- 合并已完成的大文件拆分重构: automation.go→automation_cron/script/playbook,
ldap.go→ldap_ou/ldap_users, server.go→cloud_accounts/domain/platform/region,
user.go→user_admin; 前端 Dashboard/K8s/Server/Approval/Monitor 子组件拆分
// Logan.Li
77 lines
2.1 KiB
Go
77 lines
2.1 KiB
Go
package handlers
|
|
|
|
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}
|
|
}
|