old_console/correlator/rules/action_exec.go
2024-11-02 14:12:45 +03:00

234 lines
4.6 KiB
Go

package rules
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"iwarma.ru/console/correlator/events"
"os/exec"
"strings"
"text/template"
log "github.com/sirupsen/logrus"
)
const (
ExecActionType = "exec"
)
type ExecAction struct {
Path string
Args string
Env string
Cwd string
templates struct {
path *template.Template
args *template.Template
env *template.Template
cwd *template.Template
}
}
func (action *ExecAction) GetType() string {
return ExecActionType
}
func (action ExecAction) ToInterface() (map[string]interface{}, error) {
result := make(map[string]interface{})
result["type"] = ExecActionType
result["path"] = action.Path
result["args"] = action.Args
result["env"] = action.Env
result["cwd"] = action.Cwd
return result, nil
}
func (action ExecAction) MarshalJSON() ([]byte, error) {
data, err := action.ToInterface()
if err != nil {
return nil, err
}
return json.Marshal(data)
}
func (action *ExecAction) UnmarshalJSON(b []byte) error {
cur := struct {
CurType string `json:"type"`
Path string `json:"path"`
Args string `json:"args"`
Env string `json:"env"`
Cwd string `json:"cwd"`
}{}
err := json.Unmarshal(b, &cur)
if err != nil {
return err
}
if cur.CurType != ExecActionType {
return fmt.Errorf("bad action type, Expect %v, got %v", ExecActionType, cur.CurType)
}
action.Path = cur.Path
action.Args = cur.Args
action.Env = cur.Env
action.Cwd = cur.Cwd
return nil
}
func (action *ExecAction) ParseInterface(v interface{}) error {
m, ok := v.(map[string]interface{})
if !ok {
return fmt.Errorf("can't parse %v from %T", v, v)
}
t, ok := m["type"].(string)
if !ok {
return errors.New("no type")
}
if t != ExecActionType {
return fmt.Errorf("bad type, expect %v got %v", ExecActionType, t)
}
path, ok := m["path"].(string)
if !ok {
return errors.New("no path")
}
action.Path = path
// Args isn't not required
args, ok := m["args"].(string)
if ok {
action.Args = args
}
// Env isn't required
env, ok := m["env"].(string)
if ok {
action.Env = env
}
// Cwd isn't required
cwd, ok := m["cwd"].(string)
if ok {
action.Cwd = cwd
}
return nil
}
func (action *ExecAction) Perform(events *[]*events.Event) error {
cl := log.WithFields(log.Fields{"type": ExecActionType, "event_count": len(*events)})
cl.Debug("Start action")
defer cl.Debug("End action")
var err error
// Check if we need to prepare templates
if action.templates.path == nil {
action.templates.path, err = template.New("Path").Parse(action.Path)
if err != nil {
cl.Errorf("Can't create path template: %v", err)
return err
}
action.templates.args, err = template.New("Args").Parse(action.Args)
if err != nil {
cl.Errorf("Can't create args template: %v", err)
return err
}
action.templates.env, err = template.New("Env").Parse(action.Env)
if err != nil {
cl.Errorf("Can't create env template: %v", err)
return err
}
action.templates.cwd, err = template.New("Cwd").Parse(action.Cwd)
if err != nil {
cl.Errorf("Can't create cwd template: %v", err)
return err
}
}
// Actual action
for _, event := range *events {
// Render templates
path, err := renderTemplate(action.templates.path, event)
if err != nil {
cl.Errorf("Can't render path: %v", err)
return err
}
args, err := renderTemplate(action.templates.args, event)
if err != nil {
cl.Errorf("Can't render args: %v", err)
return err
}
env, err := renderTemplate(action.templates.env, event)
if err != nil {
cl.Errorf("Can't render env: %v", err)
return err
}
cwd, err := renderTemplate(action.templates.cwd, event)
if err != nil {
cl.Errorf("Can't render cwd: %v", err)
return err
}
// Prepare command
var buf bytes.Buffer
fullArgs := make([]string, 1)
fullArgs[0] = path
for _, cur := range strings.Split(args, " ") {
fullArgs = append(fullArgs, cur)
}
cmd := &exec.Cmd{
Path: path,
Args: fullArgs,
Env: strings.Split(env, " "),
Dir: cwd,
Stdout: &buf,
Stderr: &buf,
}
debLog := log.WithFields(log.Fields{
"type": ExecActionType, "event": event.GetString("event_id"),
"path": cmd.Path, "args": cmd.Args,
"env": cmd.Env, "cwd": cmd.Dir,
})
debLog.Debugf("Starting command")
// TODO: Maybe set to goroutine
err = cmd.Start()
if err != nil {
cl.Errorf("Script execution error: %v", err)
debLog.Debugf("Executabe output:\n%v", buf.String())
return err
}
err = cmd.Wait()
if err != nil {
cl.Errorf("Error while waiting script finish: %v", err)
debLog.Debugf("Executabe output:\n%v", buf.String())
return err
}
debLog.Debugf("Executabe output:\n%v", buf.String())
}
return nil
}