f-29: watchdog: add notify #29
Signed-off-by: GnomeZworc <nicolas.boufidjeline@g3e.fr>
This commit is contained in:
parent
9445bc087a
commit
f05c4e1fce
3 changed files with 149 additions and 0 deletions
5
internal/watchdog/notify/notify.go
Normal file
5
internal/watchdog/notify/notify.go
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
package notify
|
||||||
|
|
||||||
|
type Notifier interface {
|
||||||
|
Notify(kind, name, problem string)
|
||||||
|
}
|
||||||
24
internal/watchdog/notify/stderr.go
Normal file
24
internal/watchdog/notify/stderr.go
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
package notify
|
||||||
|
|
||||||
|
import "log/slog"
|
||||||
|
|
||||||
|
var _ Notifier = (*StderrNotifier)(nil)
|
||||||
|
|
||||||
|
type StderrNotifier struct {
|
||||||
|
logger *slog.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStderr(l *slog.Logger) *StderrNotifier {
|
||||||
|
if l == nil {
|
||||||
|
l = slog.Default()
|
||||||
|
}
|
||||||
|
return &StderrNotifier{logger: l}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *StderrNotifier) Notify(kind, name, problem string) {
|
||||||
|
n.logger.Error("watchdog: incohérence détectée",
|
||||||
|
"kind", kind,
|
||||||
|
"name", name,
|
||||||
|
"problem", problem,
|
||||||
|
)
|
||||||
|
}
|
||||||
120
internal/watchdog/notify/stderr_test.go
Normal file
120
internal/watchdog/notify/stderr_test.go
Normal file
|
|
@ -0,0 +1,120 @@
|
||||||
|
package notify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"log/slog"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newTestNotifier(t *testing.T) (*StderrNotifier, *bytes.Buffer) {
|
||||||
|
t.Helper()
|
||||||
|
var buf bytes.Buffer
|
||||||
|
l := slog.New(slog.NewJSONHandler(&buf, &slog.HandlerOptions{Level: slog.LevelError}))
|
||||||
|
return NewStderr(l), &buf
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeLines(t *testing.T, buf *bytes.Buffer) []map[string]any {
|
||||||
|
t.Helper()
|
||||||
|
var out []map[string]any
|
||||||
|
for _, line := range strings.Split(strings.TrimSpace(buf.String()), "\n") {
|
||||||
|
if line == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var m map[string]any
|
||||||
|
if err := json.Unmarshal([]byte(line), &m); err != nil {
|
||||||
|
t.Fatalf("ligne non JSON %q: %v", line, err)
|
||||||
|
}
|
||||||
|
out = append(out, m)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNotify_EmetLesTroisChampsStructures(t *testing.T) {
|
||||||
|
n, buf := newTestNotifier(t)
|
||||||
|
|
||||||
|
n.Notify("vm", "i-test1", "tap12 absente du netns vp-admin")
|
||||||
|
|
||||||
|
lines := decodeLines(t, buf)
|
||||||
|
if len(lines) != 1 {
|
||||||
|
t.Fatalf("attendu 1 ligne, obtenu %d", len(lines))
|
||||||
|
}
|
||||||
|
|
||||||
|
for field, want := range map[string]string{
|
||||||
|
"kind": "vm",
|
||||||
|
"name": "i-test1",
|
||||||
|
"problem": "tap12 absente du netns vp-admin",
|
||||||
|
} {
|
||||||
|
got, ok := lines[0][field]
|
||||||
|
if !ok {
|
||||||
|
t.Errorf("champ %q absent de la sortie", field)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("champ %q = %v, attendu %q", field, got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNotify_NiveauError(t *testing.T) {
|
||||||
|
n, buf := newTestNotifier(t)
|
||||||
|
|
||||||
|
n.Notify("vpc", "vp-admin", "netns absent")
|
||||||
|
|
||||||
|
lines := decodeLines(t, buf)
|
||||||
|
if len(lines) != 1 {
|
||||||
|
t.Fatalf("attendu 1 ligne, obtenu %d", len(lines))
|
||||||
|
}
|
||||||
|
if lines[0]["level"] != "ERROR" {
|
||||||
|
t.Errorf("level = %v, attendu ERROR", lines[0]["level"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNotify_MessageNeContientPasLesValeurs(t *testing.T) {
|
||||||
|
n, buf := newTestNotifier(t)
|
||||||
|
|
||||||
|
n.Notify("subnet", "br-000042", "bridge down")
|
||||||
|
|
||||||
|
lines := decodeLines(t, buf)
|
||||||
|
msg, _ := lines[0]["msg"].(string)
|
||||||
|
for _, v := range []string{"br-000042", "bridge down"} {
|
||||||
|
if strings.Contains(msg, v) {
|
||||||
|
t.Errorf("msg %q ne devrait pas contenir la valeur %q (elle doit être un attribut)", msg, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNotify_AucuneDeduplication(t *testing.T) {
|
||||||
|
n, buf := newTestNotifier(t)
|
||||||
|
|
||||||
|
for range 3 {
|
||||||
|
n.Notify("vm", "i-test1", "qemu ne répond pas sur QMP")
|
||||||
|
}
|
||||||
|
|
||||||
|
if lines := decodeLines(t, buf); len(lines) != 3 {
|
||||||
|
t.Errorf("attendu 3 lignes (une par appel), obtenu %d", len(lines))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNotify_ChampsVides(t *testing.T) {
|
||||||
|
n, buf := newTestNotifier(t)
|
||||||
|
|
||||||
|
n.Notify("", "", "")
|
||||||
|
|
||||||
|
if lines := decodeLines(t, buf); len(lines) != 1 {
|
||||||
|
t.Errorf("attendu 1 ligne, obtenu %d", len(lines))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewStderr_LoggerNil(t *testing.T) {
|
||||||
|
n := NewStderr(nil)
|
||||||
|
if n.logger == nil {
|
||||||
|
t.Fatal("logger nil non remplacé par slog.Default()")
|
||||||
|
}
|
||||||
|
n.Notify("vpc", "vp-admin", "netns absent")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewStderr_ImplementeNotifier(t *testing.T) {
|
||||||
|
var _ Notifier = NewStderr(nil)
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue