Skip to content
Snippets Groups Projects
runner.go 2.88 KiB
Newer Older
Yoann Ono Dit Biot's avatar
Yoann Ono Dit Biot committed
package core

import (
Yoann Ono Dit Biot's avatar
Yoann Ono Dit Biot committed
	"errors"
	"fmt"
	"github.com/panjf2000/ants"
Yoann Ono Dit Biot's avatar
Yoann Ono Dit Biot committed
	"leviathan/libs"
Yoann Ono Dit Biot's avatar
Yoann Ono Dit Biot committed
	"leviathan/utils"
	"os"
	"path"
	"sync"
Yoann Ono Dit Biot's avatar
Yoann Ono Dit Biot committed
)

type Runner struct {
Yoann Ono Dit Biot's avatar
Yoann Ono Dit Biot committed
	Target    string
	Workspace string
	Workflow  libs.Workflow
	Options   *libs.Options
Yoann Ono Dit Biot's avatar
Yoann Ono Dit Biot committed
}

Yoann Ono Dit Biot's avatar
Yoann Ono Dit Biot committed
func InitRunner(target string, options *libs.Options) (Runner, error) {
Yoann Ono Dit Biot's avatar
Yoann Ono Dit Biot committed
	var runner Runner
	runner.Target = target
Yoann Ono Dit Biot's avatar
Yoann Ono Dit Biot committed
	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
	}

Yoann Ono Dit Biot's avatar
Yoann Ono Dit Biot committed
	return runner, nil
}

Yoann Ono Dit Biot's avatar
Yoann Ono Dit Biot committed
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
}

Yoann Ono Dit Biot's avatar
Yoann Ono Dit Biot committed
func (r *Runner) Start() {
Yoann Ono Dit Biot's avatar
Yoann Ono Dit Biot committed
	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)
Yoann Ono Dit Biot's avatar
Yoann Ono Dit Biot committed

}