From 315a334732a2152cd49f7c0d8068b45bf0d8d3d9 Mon Sep 17 00:00:00 2001 From: Bazaah Date: Fri, 9 Dec 2022 12:34:03 +0000 Subject: [PATCH] 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. --- handler/handler.go | 85 +++++++++++++++++++++++++++++++++++++++++++++ handler/template.go | 52 +++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 handler/handler.go create mode 100644 handler/template.go diff --git a/handler/handler.go b/handler/handler.go new file mode 100644 index 0000000..8a64608 --- /dev/null +++ b/handler/handler.go @@ -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, + }, + } +} diff --git a/handler/template.go b/handler/template.go new file mode 100644 index 0000000..fc77018 --- /dev/null +++ b/handler/template.go @@ -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()), + ) + } +}