-
Yoann Ono Dit Biot authoredYoann Ono Dit Biot authored
runner.go 2.88 KiB
package core
import (
"errors"
"fmt"
"github.com/panjf2000/ants"
"leviathan/libs"
"leviathan/utils"
"os"
"path"
"sync"
)
type Runner struct {
Target string
Workspace string
Workflow libs.Workflow
Options *libs.Options
}
func InitRunner(target string, options *libs.Options) (Runner, error) {
var runner Runner
runner.Target = target
runner.Options = options
runner.Workspace = path.Join(options.Environment.Workspaces, utils.CleanPath(target))
if _, err := os.Stat(runner.Workspace); os.IsNotExist(err) {
utils.Logger.Debug().Str("workspace", runner.Workspace).Msg("Create workspace folder")
if err = os.MkdirAll(runner.Workspace, 0700); err != nil {
return runner, err
}
}
if err := PrepareWorkflow(&runner); err != nil {
return runner, err
}
return runner, nil
}
func PrepareWorkflow(r *Runner) error {
// check if workflow exists
utils.Logger.Debug().Str("workflow", r.Options.Scan.Flow).Msg("Check if workflow exists")
if !WorkflowExists(r.Options.Scan.Flow, r.Options.Environment.Workflows) {
return errors.New(fmt.Sprintf("%s workflow was not found", r.Options.Scan.Flow))
}
// parse workflow
utils.Logger.Debug().Str("workflow", r.Options.Scan.Flow).Msg("Try to parse workflow")
workflow, err := WorkflowParse(r)
if err != nil {
return err
}
r.Workflow = workflow
// retrieve all modules used by the workflow
for id, routine := range workflow.Routines {
var modules []libs.Module
for _, moduleName := range routine.Modules {
utils.Logger.Debug().Str("module", moduleName).Msg("Try to parse module")
module, err := ModuleParse(moduleName, r)
if err != nil {
return err
}
modules = append(modules, module)
}
workflow.Routines[id].ModulesParsed = modules
}
return nil
}
func (r *Runner) Start() {
utils.Logger.Info().
Str("runner", r.Target).
Str("workflow", r.Workflow.Name).
Msg("Start runner")
for _, routine := range r.Workflow.Routines {
var wg sync.WaitGroup
p, _ := ants.NewPoolWithFunc(r.Options.Scan.Threads*10, func(m interface{}) {
module := m.(libs.Module)
r.RunModule(module)
wg.Done()
}, ants.WithPreAlloc(true))
defer p.Release()
for _, module := range routine.ModulesParsed {
p.Invoke(module)
wg.Add(1)
}
wg.Wait()
}
}
func (r *Runner) RunModule(m libs.Module) {
utils.Logger.Info().Str("module", m.Name).Msg("Run module")
utils.Logger.Debug().Str("module", m.Name).Msg("Execute Pre_run commands")
r.runScripts(m.PreRun)
utils.Logger.Debug().Str("module", m.Name).Msg("Execute Steps commands")
for _, step := range m.Steps {
// Check requirements
if !r.CheckRequirements(step.Requirements) {
utils.Logger.Info().Msg("Skip step")
continue
}
// Check conditions
// Execute commands
r.runCommands(step.Commands)
// Execute scripts
r.runScripts(step.Scripts)
}
utils.Logger.Debug().Str("module", m.Name).Msg("Execute Post_run commands")
r.runScripts(m.PostRun)
}