handler: types and funcs for handling notify events

The primary type exported is VrrpHandler, which interprets the given
WatchRules, applying them as necessary.

It implements watcher.MsgHandler, and can be considered the primary
implementation.
This commit is contained in:
Paul Stemmet 2022-12-09 12:34:03 +00:00
parent 256351013b
commit 315a334732
Signed by: Paul Stemmet
GPG Key ID: EDEA539F594E7E75
2 changed files with 137 additions and 0 deletions

85
handler/handler.go Normal file
View File

@ -0,0 +1,85 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package handler
import (
"text/template"
"git.st8l.com/luxolus/kdnotify/config"
n "git.st8l.com/luxolus/kdnotify/schema/notify"
)
type VrrpHandler struct {
Config *config.WatchConfig
Cxt *config.LibCxt
}
type TemplateEnv struct {
Cxt any
Event MessageEvent
}
type MessageEvent struct {
Type string
State string
Instance string
}
func NewVrrp(cxt *config.LibCxt, cfg *config.WatchConfig) *VrrpHandler {
return &VrrpHandler{
Config: cfg,
Cxt: &config.LibCxt{
Logger: cxt.Logger.Named("handler"),
Context: cxt.Context,
},
}
}
func (h *VrrpHandler) ProcessVrrp(msg n.VrrpMessage) error {
log, matches := h.Cxt.Logger.Sugar(), 0
for _, rule := range h.Config.Rules {
if rule.Match(&msg) {
matches += 1
env := h.newTemplateEnv(&msg)
err := h.execTemplate(rule.Exec, &env)
if err != nil {
log.Warnw("failed to evaluate rule", "instance", msg.Instance, "error", err)
}
}
}
log.Debugw("processed VRRP message", "instance", msg.Instance, "rules", matches)
return nil
}
func (h *VrrpHandler) execTemplate(t *template.Template, env *TemplateEnv) error {
cmdline, err := runTemplate(t, env)
if err != nil {
return err
}
cmd, err := mkCmd(cmdline)
if err != nil {
return err
}
go execRuleCmd(cmd, h.Cxt.Logger)
return nil
}
func (h *VrrpHandler) newTemplateEnv(msg *n.VrrpMessage) TemplateEnv {
return TemplateEnv{
Cxt: h.Config.Context,
Event: MessageEvent{
Type: msg.Type.String(),
State: msg.State.String(),
Instance: msg.Instance,
},
}
}

52
handler/template.go Normal file
View File

@ -0,0 +1,52 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package handler
import (
"fmt"
"os/exec"
"strings"
"text/template"
"github.com/mattn/go-shellwords"
"go.uber.org/zap"
)
func runTemplate(t *template.Template, env *TemplateEnv) (string, error) {
var buf strings.Builder
err := t.Execute(&buf, env)
if err != nil {
return "", fmt.Errorf("unable to parse exec template: %w", err)
}
return buf.String(), nil
}
func mkCmd(cmdline string) (*exec.Cmd, error) {
args, err := shellwords.Parse(cmdline)
if err != nil {
return nil, fmt.Errorf("unable to parse exec line: %w", err)
}
if len(args) < 1 {
return nil, fmt.Errorf("exec line evaluated as empty")
}
return exec.Command(args[0], args[1:]...), nil
}
func execRuleCmd(c *exec.Cmd, l *zap.Logger) {
err := c.Run()
if err != nil {
l.Named("exec").Warn(
"watch exec failed",
zap.String("cmd", c.String()),
zap.String("error", err.Error()),
)
}
}