package module import ( "fmt" "strings" "gorm.io/gorm" "ops-assistant/internal/core/ecode" "ops-assistant/internal/core/policy" "ops-assistant/internal/core/runbook" ) type Runner struct { db *gorm.DB exec *runbook.Executor } func NewRunner(db *gorm.DB, exec *runbook.Executor) *Runner { return &Runner{db: db, exec: exec} } func (r *Runner) Run(commandText string, operator int64, req Request) (uint, string, error) { if strings.TrimSpace(req.RunbookName) == "" { return 0, "", fmt.Errorf(ecode.Tag(ecode.ErrStepFailed, "runbook 不能为空")) } if req.DryRun { if !req.Gate.AllowDryRun { return 0, "", fmt.Errorf(ecode.Tag(ecode.ErrStepFailed, "当前命令不允许 dry-run")) } return 0, "dry-run", nil } if err := policy.CheckGate(r.db, policy.GateRequest{ NeedFlag: req.Gate.NeedFlag, RequireConfirm: req.Gate.RequireConfirm, ConfirmToken: req.ConfirmToken, ExpectedToken: req.Gate.ExpectedToken, AllowDryRun: req.Gate.AllowDryRun, DryRun: req.DryRun, }); err != nil { code := ecode.ErrFeatureDisabled if strings.Contains(err.Error(), "confirm") || strings.Contains(err.Error(), "确认") { code = ecode.ErrConfirmRequired } return 0, "", fmt.Errorf(ecode.Tag(code, err.Error())) } return r.exec.RunWithInputsAndMeta(commandText, req.RunbookName, operator, req.Inputs, req.Meta) }