184 lines
4.1 KiB
Go
184 lines
4.1 KiB
Go
package rules
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"iwarma.ru/console/correlator/events"
|
|
"log/syslog"
|
|
"strconv"
|
|
"text/template"
|
|
|
|
"github.com/spf13/viper"
|
|
"iwarma.ru/console/correlator/config"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
const (
|
|
SyslogProtoTcp = "tcp"
|
|
SyslogProtoUdp = "udp"
|
|
|
|
SyslogActionType = "syslog"
|
|
)
|
|
|
|
// SyslogAction Send record with syslog to selected host
|
|
type SyslogAction struct {
|
|
Host string
|
|
Port int
|
|
Proto string
|
|
Name string
|
|
Template string
|
|
writer *syslog.Writer
|
|
bodyTemplate *template.Template
|
|
}
|
|
|
|
func (action SyslogAction) GetType() string {
|
|
return SyslogActionType
|
|
}
|
|
|
|
func (action SyslogAction) Perform(events *[]*events.Event) error {
|
|
contextLogger := log.WithFields(log.Fields{"type": SyslogActionType, "event_count": len(*events)})
|
|
contextLogger.Debug("Start action")
|
|
defer contextLogger.Debug("End action")
|
|
|
|
if events == nil {
|
|
contextLogger.Error("Nil events provided")
|
|
return errors.New("nil events provided")
|
|
}
|
|
|
|
// Create connection to syslog server
|
|
if action.writer == nil {
|
|
if action.Proto != SyslogProtoTcp && action.Proto != SyslogProtoUdp {
|
|
return fmt.Errorf("bad syslog protocol %v", action.Proto)
|
|
}
|
|
writer, err := syslog.Dial(action.Proto, fmt.Sprintf("%v:%v", action.Host, action.Port), syslog.LOG_LOCAL0, viper.GetString(config.SyslogTag))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
action.writer = writer
|
|
}
|
|
|
|
// Create template
|
|
if action.bodyTemplate == nil {
|
|
bodyTemplate, err := template.New("Action").Parse(action.Template)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
action.bodyTemplate = bodyTemplate
|
|
}
|
|
|
|
// Send messages
|
|
for _, cur := range *events {
|
|
var buf bytes.Buffer
|
|
err := action.bodyTemplate.Execute(&buf, *cur)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = action.writer.Info(buf.String())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (action SyslogAction) MarshalJSON() ([]byte, error) {
|
|
return json.Marshal(struct {
|
|
CurType string `json:"type"`
|
|
Host string `json:"host"`
|
|
Port string `json:"port"`
|
|
Proto string `json:"protocol"`
|
|
Name string `json:"name"`
|
|
Format string `json:"format"`
|
|
Template string `json:"template"`
|
|
}{
|
|
CurType: SyslogActionType,
|
|
Host: action.Host,
|
|
Port: strconv.Itoa(action.Port),
|
|
Proto: action.Proto,
|
|
Name: action.Name,
|
|
Format: "",
|
|
Template: action.Template,
|
|
})
|
|
}
|
|
|
|
func (action *SyslogAction) UnmarshalJSON(b []byte) error {
|
|
cur := struct {
|
|
CurType string `json:"type"`
|
|
Host string `json:"host"`
|
|
Port string `json:"port"`
|
|
Proto string `json:"protocol"`
|
|
Name string `json:"name"`
|
|
Format string `json:"format"`
|
|
Template string `json:"template"`
|
|
}{}
|
|
|
|
err := json.Unmarshal(b, &cur)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if cur.CurType != SyslogActionType {
|
|
return fmt.Errorf("bad action type. Expect http, got %s", cur.CurType)
|
|
}
|
|
|
|
action.Host = cur.Host
|
|
action.Port, err = strconv.Atoi(cur.Port)
|
|
if err != nil {
|
|
return fmt.Errorf("can't parse port: %v", cur.Port)
|
|
}
|
|
action.Proto = cur.Proto
|
|
action.Name = cur.Name
|
|
action.Template = cur.Template
|
|
|
|
return nil
|
|
}
|
|
|
|
func (action *SyslogAction) ParseInterface(v interface{}) error {
|
|
m, ok := v.(map[string]interface{})
|
|
if !ok {
|
|
return fmt.Errorf("can't parse %v from %T", v, v)
|
|
}
|
|
|
|
action.Host, ok = m["host"].(string)
|
|
if !ok {
|
|
return errors.New("can't get host")
|
|
}
|
|
|
|
// Port can bee int (float64) or string
|
|
if port, ok := m["port"].(float64); ok {
|
|
action.Port = int(port)
|
|
} else if port, ok := m["port"].(string); ok {
|
|
cur, err := strconv.Atoi(port)
|
|
if err != nil {
|
|
return fmt.Errorf("bad port string: %v", port)
|
|
}
|
|
action.Port = cur
|
|
} else {
|
|
return fmt.Errorf("bad port type: %T with value %v", port, port)
|
|
}
|
|
|
|
action.Proto, ok = m["protocol"].(string)
|
|
if !ok {
|
|
return errors.New("can't get protocol")
|
|
}
|
|
|
|
action.Name, ok = m["name"].(string)
|
|
if !ok {
|
|
return errors.New("can't get name")
|
|
}
|
|
|
|
// Template can be in data or template
|
|
if action.Template, ok = m["data"].(string); !ok {
|
|
if action.Template, ok = m["template"].(string); !ok {
|
|
return errors.New("can't get template")
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|